Almost done!
Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
parent
8cb3efc70f
commit
dc2d97196e
@ -175,7 +175,7 @@
|
||||
|
||||
[data-color='O'] > .Corner-Shape,
|
||||
[data-color='O'] > .Road-Shape {
|
||||
background-color: rgba(255, 196, 0, 1);
|
||||
background-color: rgb(255, 128, 0);
|
||||
}
|
||||
|
||||
[data-color='W'] > .Corner-Shape,
|
||||
|
@ -70,7 +70,7 @@ const Board = ({ table, game }) => {
|
||||
|
||||
const Corner = ({corner}) => {
|
||||
const onClick = (event) => {
|
||||
console.log(`Corner ${corner.index}:`, game.layout.corners[corner.index]);
|
||||
// console.log(`Corner ${corner.index}:`, game.layout.corners[corner.index]);
|
||||
if (event.currentTarget.getAttribute('data-type') === 'settlement') {
|
||||
table.placeCity(corner.index);
|
||||
} else {
|
||||
@ -91,7 +91,7 @@ const Board = ({ table, game }) => {
|
||||
|
||||
const Pip = ({pip}) => {
|
||||
const onClick = (event) => {
|
||||
console.log(`Pip ${pip.index}:`, game.layout.corners[pip.index]);
|
||||
// console.log(`Pip ${pip.index}:`, game.layout.corners[pip.index]);
|
||||
table.placeRobber(pip.index);
|
||||
return;
|
||||
};
|
||||
@ -377,14 +377,23 @@ const Board = ({ table, game }) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (game && game.turn && game.turn.roll) {
|
||||
let nodes = document.querySelectorAll('.Pip.Active');
|
||||
if (game && game.turn) {
|
||||
let nodes = document.querySelectorAll('.Active');
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
nodes[i].classList.remove('Active');
|
||||
}
|
||||
nodes = document.querySelectorAll(`.Pip[data-roll="${game.turn.roll}"]`);
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
nodes[i].classList.add('Active');
|
||||
if (game.turn.roll) {
|
||||
nodes = document.querySelectorAll(`.Pip[data-roll="${game.turn.roll}"]`);
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const index = nodes[i].getAttribute('data-index');
|
||||
if (index !== null) {
|
||||
const tile = document.querySelector(`.Tile[data-index="${index}"]`);
|
||||
if (tile) {
|
||||
tile.classList.add('Active');
|
||||
}
|
||||
}
|
||||
nodes[i].classList.add('Active');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
.Resource {
|
||||
position: relative;
|
||||
width: 4.9em;
|
||||
height: 7.2em;
|
||||
height: 7em;
|
||||
width: 5em;
|
||||
display: inline-block;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
margin: 0.25em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.Resource:hover {
|
||||
|
@ -196,6 +196,11 @@
|
||||
filter: brightness(150%);
|
||||
}
|
||||
|
||||
.Development.Selected {
|
||||
filter: brightness(150%);
|
||||
top: -1em;
|
||||
}
|
||||
|
||||
.Game {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
@ -219,9 +224,6 @@
|
||||
}
|
||||
|
||||
.Game.lobby {
|
||||
max-width: 100vw;
|
||||
width: 100vw;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -366,7 +368,9 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-items: space-between;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.Placard > div {
|
||||
box-sizing: border-box;
|
||||
margin: 0 0.9em;
|
||||
@ -407,6 +411,7 @@
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
margin: 0.25em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.Action {
|
||||
|
@ -14,8 +14,7 @@ import { assetsPath, base, getPlayerName, gamesPath } from './Common.js';
|
||||
import PlayerColor from './PlayerColor.js';
|
||||
import Dice from './Dice.js';
|
||||
import Resource from './Resource.js';
|
||||
|
||||
//import moment from 'moment';
|
||||
import ViewCard from './ViewCard.js';
|
||||
|
||||
/* Start of withRouter polyfill */
|
||||
// https://reactrouter.com/docs/en/v6/faq#what-happened-to-withrouter-i-need-it
|
||||
@ -106,9 +105,10 @@ const Placard = ({table, type, active}) => {
|
||||
);
|
||||
};
|
||||
|
||||
const Development = ({table, type}) => {
|
||||
const Development = ({table, type, card, onClick}) => {
|
||||
return (
|
||||
<div className="Development"
|
||||
<div className={`Development ${card.played ? 'Selected' : ''}`}
|
||||
onClick={onClick}
|
||||
style={{
|
||||
backgroundImage:`url(${assetsPath}/gfx/card-${type}.png)`
|
||||
}}/>
|
||||
@ -293,7 +293,7 @@ const GameOrder = ({table}) => {
|
||||
<div className="GameOrderPlayer" key={`player-${item.color}`}>
|
||||
<PlayerColor color={item.color}/>
|
||||
<div>{item.name}</div>
|
||||
{ item.orderRoll !== 0 && <>rolled <Dice pips={item.orderRoll}/>.</> }
|
||||
{ item.orderRoll !== 0 && <>rolled <Dice pips={item.orderRoll}/>. {item.orderStatus}</> }
|
||||
{ item.orderRoll === 0 && <>has not rolled yet. {item.orderStatus}</>}
|
||||
</div>
|
||||
);
|
||||
@ -352,7 +352,7 @@ const Action = ({ table }) => {
|
||||
};
|
||||
|
||||
const discardClick = (event) => {
|
||||
const nodes = document.querySelectorAll('.Hand .Selected'),
|
||||
const nodes = document.querySelectorAll('.Hand .Resource.Selected'),
|
||||
discarding = { wheat: 0, brick: 0, sheep: 0, stone: 0, wood: 0 };
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
discarding[nodes[i].getAttribute("data-type")]++;
|
||||
@ -386,23 +386,26 @@ const Action = ({ table }) => {
|
||||
return (<Paper className="Action"/>);
|
||||
}
|
||||
|
||||
const inLobby = table.game.state === 'lobby',
|
||||
player = table.game ? table.game.player : undefined,
|
||||
hasRolled = (table.game && table.game.turn && table.game.turn.roll) ? true : false,
|
||||
isTurn = (table.game && table.game.turn && table.game.turn.color === table.game.color) ? true : false,
|
||||
robberActions = (table.game && table.game.turn && table.game.turn.roll === 7 && !table.game.turn.robberDone);
|
||||
const game = table.game,
|
||||
inLobby = game.state === 'lobby',
|
||||
player = game ? game.player : undefined,
|
||||
hasRolled = (game && game.turn && game.turn.roll) ? true : false,
|
||||
isTurn = (game && game.turn && game.turn.color === game.color) ? true : false,
|
||||
robberActions = (game && game.turn && game.turn.roll === 7 &&
|
||||
!game.turn.robberDone),
|
||||
haveResources = player ? player.haveResources : false;
|
||||
|
||||
return (
|
||||
<Paper className="Action">
|
||||
{ inLobby && <>
|
||||
<StartButton table={table}/>
|
||||
<Button disabled={table.game.color ? false : true} onClick={newTableClick}>New table</Button>
|
||||
<Button disabled={table.game.color ? true : false} onClick={() => {table.setState({ pickName: true})}}>Change name</Button> </> }
|
||||
{ table.game.state === 'normal' && <>
|
||||
<Button disabled={game.color ? false : true} onClick={newTableClick}>New table</Button>
|
||||
<Button disabled={game.color ? true : false} onClick={() => {table.setState({ pickName: true})}}>Change name</Button> </> }
|
||||
{ game.state === 'normal' && <>
|
||||
<Button disabled={robberActions || !isTurn || hasRolled} onClick={rollClick}>Roll Dice</Button>
|
||||
<Button disabled={robberActions || !isTurn || !hasRolled} onClick={tradeClick}>Trade</Button>
|
||||
<Button disabled={robberActions || !isTurn || !hasRolled} onClick={buildClicked}>Build</Button>
|
||||
{ table.game.turn.roll === 7 && player && player.mustDiscard > 0 &&
|
||||
<Button disabled={robberActions || !isTurn || !hasRolled || !haveResources} onClick={tradeClick}>Trade</Button>
|
||||
<Button disabled={robberActions || !isTurn || !hasRolled || !haveResources} onClick={buildClicked}>Build</Button>
|
||||
{ game.turn.roll === 7 && player && player.mustDiscard > 0 &&
|
||||
<Button onClick={discardClick}>Discard</Button>
|
||||
}
|
||||
<Button disabled={robberActions || !isTurn || !hasRolled} onClick={passClick}>Done</Button>
|
||||
@ -468,7 +471,12 @@ const Players = ({ table }) => {
|
||||
}
|
||||
const name = getPlayerName(table.game.sessions, color),
|
||||
selectable = table.game.state === 'lobby' && (item.status === 'Not active' || table.game.color === color);
|
||||
let toggleText = name ? name : "Available";
|
||||
let toggleText;
|
||||
if (name) {
|
||||
toggleText = `${name} has ${item.points} VP`;
|
||||
} else {
|
||||
toggleText = "Available";
|
||||
}
|
||||
players.push((
|
||||
<div
|
||||
data-selectable={selectable}
|
||||
@ -511,7 +519,8 @@ class Table extends React.Component {
|
||||
message: "",
|
||||
error: "",
|
||||
signature: "",
|
||||
buildActive: false
|
||||
buildActive: false,
|
||||
cardActive: undefined
|
||||
};
|
||||
this.componentDidMount = this.componentDidMount.bind(this);
|
||||
this.updateDimensions = this.updateDimensions.bind(this);
|
||||
@ -524,6 +533,7 @@ class Table extends React.Component {
|
||||
this.startTrading = this.startTrading.bind(this);
|
||||
this.offerTrade = this.offerTrade.bind(this);
|
||||
this.acceptTrade = this.acceptTrade.bind(this);
|
||||
this.rejectTrade = this.rejectTrade.bind(this);
|
||||
this.cancelTrading = this.cancelTrading.bind(this);
|
||||
this.discard = this.discard.bind(this);
|
||||
this.passTurn = this.passTurn.bind(this);
|
||||
@ -534,6 +544,8 @@ class Table extends React.Component {
|
||||
this.gameSignature = this.gameSignature.bind(this);
|
||||
this.sendAction = this.sendAction.bind(this);
|
||||
this.buildClicked = this.buildClicked.bind(this);
|
||||
this.closeCard = this.closeCard.bind(this);
|
||||
this.playCard = this.playCard.bind(this);
|
||||
|
||||
this.mouse = { x: 0, y: 0 };
|
||||
this.radius = 0.317;
|
||||
@ -556,6 +568,10 @@ class Table extends React.Component {
|
||||
this.id = (props.router && props.router.params.id) ? props.router.params.id : 0;
|
||||
}
|
||||
|
||||
closeCard() {
|
||||
this.setState({cardActive: undefined});
|
||||
}
|
||||
|
||||
sendAction(action, value, extra) {
|
||||
if (this.loadTimer) {
|
||||
window.clearTimeout(this.loadTimer);
|
||||
@ -596,6 +612,11 @@ class Table extends React.Component {
|
||||
return this.sendAction('chat', undefined, {message: message});
|
||||
}
|
||||
|
||||
playCard(card) {
|
||||
this.setState({ cardActive: undefined });
|
||||
return this.sendAction('play-card', undefined, card);
|
||||
}
|
||||
|
||||
setPlayerName(name) {
|
||||
return this.sendAction('player-name', name)
|
||||
.then(() => {
|
||||
@ -626,6 +647,10 @@ class Table extends React.Component {
|
||||
return this.sendAction('trade', 'accept', trade);
|
||||
}
|
||||
|
||||
rejectTrade(trade) {
|
||||
return this.sendAction('trade', 'reject', trade);
|
||||
}
|
||||
|
||||
discard(resources) {
|
||||
return this.sendAction('discard', undefined, resources);
|
||||
}
|
||||
@ -833,7 +858,7 @@ class Table extends React.Component {
|
||||
break;
|
||||
case 'game-order':
|
||||
if (!player) {
|
||||
message = <>{message}This game as an observer as <b>{name}</b>.</>;
|
||||
message = <>{message}You are an observer in this game as <b>{name}</b>.</>;
|
||||
message = <>{message}You can chat with other players below as <b>{this.game.name}</b>, but cannot play unless players go back to the Lobby.</>;
|
||||
} else {
|
||||
if (!player.order) {
|
||||
@ -967,6 +992,14 @@ class Table extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
cardClicked(card) {
|
||||
const game = this.state.game;
|
||||
if (!game) {
|
||||
return;
|
||||
}
|
||||
this.setState({cardActive: card });
|
||||
}
|
||||
|
||||
render() {
|
||||
const game = this.state.game,
|
||||
player = game ? game.player : undefined
|
||||
@ -980,15 +1013,25 @@ class Table extends React.Component {
|
||||
let development;
|
||||
if (player) {
|
||||
let stacks = {};
|
||||
game.player.development.forEach(item => (item.type in stacks) ? stacks[item.type].push(item.card) : stacks[item.type] = [item.card]);
|
||||
game.player.development.forEach(card =>
|
||||
(card.type in stacks)
|
||||
? stacks[card.type].push(card)
|
||||
: stacks[card.type] = [card]);
|
||||
|
||||
development = [];
|
||||
for (let type in stacks) {
|
||||
const cards = stacks[type].map(card => <Development table={this} key={`${type}-${card}`} type={`${type}-${card}`}/>);
|
||||
const cards = stacks[type].map(card => <Development
|
||||
onClick={() => this.cardClicked(card)}
|
||||
card={card}
|
||||
table={this}
|
||||
key={`${type}-${card.card}`}
|
||||
type={`${type}-${card.card}`}/>);
|
||||
development.push(<div key={type} className="Stack">{ cards }</div>);
|
||||
}
|
||||
} else {
|
||||
development = <>/</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="Table">
|
||||
|
||||
@ -1030,6 +1073,10 @@ class Table extends React.Component {
|
||||
</> }
|
||||
</div> }
|
||||
|
||||
{ this.state.cardActive &&
|
||||
<ViewCard table={this} card={this.state.cardActive}/>
|
||||
}
|
||||
|
||||
{ game && game.state === 'game-order' &&
|
||||
<GameOrder table={this}/>
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
background-color:rgba(224, 224, 224);
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
.Trade > * {
|
||||
min-width: 40em;
|
||||
display: inline-flex;
|
||||
@ -29,6 +30,11 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.Trade .Resource {
|
||||
width: 3.75em; /* 5x7 aspect ratio */
|
||||
height: 5.25em;
|
||||
}
|
||||
|
||||
.Trade .PlayerColor {
|
||||
width: 0.5em;
|
||||
height: 0.5em;
|
||||
|
@ -6,14 +6,13 @@ import Paper from '@material-ui/core/Paper';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Resource from './Resource.js';
|
||||
|
||||
const ResourceCounter = ({type, onCount, max}) => {
|
||||
const [count, setCount] = useState(0);
|
||||
const ResourceCounter = ({type, count, onCount, max}) => {
|
||||
count = count ? count : 0;
|
||||
const plusClicked = (event) => {
|
||||
if (max === undefined || max > count) {
|
||||
if (onCount) {
|
||||
onCount(type, count+1);
|
||||
}
|
||||
setCount(count+1);
|
||||
}
|
||||
};
|
||||
const minusClicked = (event) => {
|
||||
@ -21,7 +20,6 @@ const ResourceCounter = ({type, onCount, max}) => {
|
||||
if (onCount) {
|
||||
onCount(type, count-1);
|
||||
}
|
||||
setCount(count-1);
|
||||
}
|
||||
};
|
||||
|
||||
@ -77,7 +75,7 @@ const Trade = ({table}) => {
|
||||
} else {
|
||||
setGiveLine(items.join(', '));
|
||||
}
|
||||
}, [setGiveLine, setGives]);
|
||||
}, [setGiveLine, setGives, gives]);
|
||||
|
||||
const getCount = useCallback((type, count) => {
|
||||
gets[type] = count;
|
||||
@ -94,12 +92,25 @@ const Trade = ({table}) => {
|
||||
} else {
|
||||
setGetLine(items.join(', '));
|
||||
}
|
||||
}, [setGetLine, setGets]);
|
||||
}, [setGetLine, setGets, gets]);
|
||||
|
||||
const meetClicked = useCallback((offer) => {
|
||||
const trade = {
|
||||
gives: offer.gets.slice(),
|
||||
gets: offer.gives.slice()
|
||||
};
|
||||
console.log(trade);
|
||||
trade.gives.forEach(give => giveCount(give.type, give.count));
|
||||
trade.gets.forEach(get => getCount(get.type, get.count));
|
||||
table.offerTrade(trade);
|
||||
}, [giveCount, getCount]);
|
||||
|
||||
if (!table.game) {
|
||||
return (<></>);
|
||||
}
|
||||
|
||||
const game = table.game;
|
||||
|
||||
const isTurn = (table.game.turn && table.game.turn.color === table.game.color) ? true : false;
|
||||
|
||||
const offerClicked = (event) => {
|
||||
@ -124,6 +135,12 @@ const Trade = ({table}) => {
|
||||
table.cancelTrading();
|
||||
}
|
||||
|
||||
/* Non-current player has rejected the active player's
|
||||
* bid */
|
||||
const rejectClicked = (trade) => {
|
||||
table.rejectTrade(trade);
|
||||
}
|
||||
|
||||
let players = [];
|
||||
for (let color in table.game.players) {
|
||||
const item = table.game.players[color],
|
||||
@ -134,7 +151,8 @@ const Trade = ({table}) => {
|
||||
color: color,
|
||||
valid: false,
|
||||
gets: item.gets ? item.gets : [],
|
||||
gives: item.gives ? item.gives : []
|
||||
gives: item.gives ? item.gives : [],
|
||||
offerRejected: item.offerRejected ? true : false
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -164,6 +182,13 @@ const Trade = ({table}) => {
|
||||
});
|
||||
}
|
||||
|
||||
const player = (table.game && table.game.player) ? table.game.player : undefined;
|
||||
if (!player) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
let canAccept = false;
|
||||
|
||||
if (table.game.turn.offer) {
|
||||
players.forEach(trade => {
|
||||
let valid = trade.gets.length && trade.gives.length;
|
||||
@ -187,9 +212,29 @@ const Trade = ({table}) => {
|
||||
});
|
||||
trade.valid = valid;
|
||||
});
|
||||
|
||||
canAccept = true;
|
||||
table.game.turn.offer.gets.forEach(item => {
|
||||
if (!canAccept) {
|
||||
canAccept = (item.type in game.player);
|
||||
}
|
||||
if (!canAccept) {
|
||||
return;
|
||||
}
|
||||
canAccept = (game.player[item.type] >= item.count);
|
||||
});
|
||||
}
|
||||
|
||||
players = players.map((item, index) => {
|
||||
if (item.offerRejected) {
|
||||
return <div className="TradePlayer" key={`player-${item.name}-${index}`}>
|
||||
<PlayerColor color={item.color}/>
|
||||
<div>{item.name}</div>
|
||||
<div className='TradeLine'>
|
||||
has rejected your offer.
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
const gets = item.gets.map(get =>
|
||||
`${get.count} ${(get.type === 'bank') ? 'of any one resource' : get.type}`)
|
||||
.join(', '),
|
||||
@ -211,16 +256,18 @@ const Trade = ({table}) => {
|
||||
}
|
||||
{ isTurn && <Button disabled={!item.valid}
|
||||
onClick={() => acceptClicked(item)}>accept</Button> }
|
||||
{ !isTurn && item.color === table.game.turn.color && <>
|
||||
<Button disabled={!canAccept}
|
||||
onClick={() => meetClicked(item)}>meet</Button>
|
||||
<Button disabled={!item.gets.length ||
|
||||
!item.gives.length || player.offerRejected}
|
||||
onClick={() => rejectClicked(item)}>reject</Button>
|
||||
</> }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
const player = (table.game && table.game.player) ? table.game.player : undefined;
|
||||
if (!player) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="Trade">
|
||||
<Paper>
|
||||
@ -230,32 +277,35 @@ const Trade = ({table}) => {
|
||||
<div className="PlayerList">
|
||||
{ players }
|
||||
</div>
|
||||
<div className='TradeLine'
|
||||
style={{
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start'
|
||||
}}>
|
||||
<div style={{display: 'flex' }}>
|
||||
<b>You want to receive {getLine}.</b>
|
||||
{ !player.haveResources && <b>You have no resources to participate in this trade.</b> }
|
||||
{ player.haveResources &&
|
||||
<div className='TradeLine'
|
||||
style={{
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start'
|
||||
}}>
|
||||
<div style={{display: 'flex' }}>
|
||||
<b>You want to receive {getLine}.</b>
|
||||
</div>
|
||||
<div style={{display: 'flex' }}>
|
||||
<ResourceCounter count={gets.brick} onCount={getCount} type='brick'/>
|
||||
<ResourceCounter count={gets.wood} onCount={getCount} type='wood'/>
|
||||
<ResourceCounter count={gets.wheat} onCount={getCount} type='wheat'/>
|
||||
<ResourceCounter count={gets.sheep} onCount={getCount} type='sheep'/>
|
||||
<ResourceCounter count={gets.stone} onCount={getCount} type='stone'/>
|
||||
</div>
|
||||
<div style={{display: 'flex' }}>
|
||||
<b>You are willing to give {giveLine}.</b>
|
||||
</div>
|
||||
<div style={{display: 'flex' }}>
|
||||
{ player.brick > 0 && <ResourceCounter count={gives.brick} onCount={giveCount} type='brick' max={player.brick}/> }
|
||||
{ player.wood > 0 && <ResourceCounter count={gives.wood} onCount={giveCount} type='wood' max={player.wood}/> }
|
||||
{ player.wheat > 0 && <ResourceCounter count={gives.wheat} onCount={giveCount} type='wheat' max={player.wheat}/> }
|
||||
{ player.sheep > 0 && <ResourceCounter count={gives.sheep} onCount={giveCount} type='sheep' max={player.sheep}/> }
|
||||
{ player.stone > 0 && <ResourceCounter count={gives.stone} onCount={giveCount} type='stone' max={player.stone}/> }
|
||||
</div>
|
||||
</div>
|
||||
<div style={{display: 'flex' }}>
|
||||
<ResourceCounter onCount={getCount} type='brick'/>
|
||||
<ResourceCounter onCount={getCount} type='wood'/>
|
||||
<ResourceCounter onCount={getCount} type='wheat'/>
|
||||
<ResourceCounter onCount={getCount} type='sheep'/>
|
||||
<ResourceCounter onCount={getCount} type='stone'/>
|
||||
</div>
|
||||
<div style={{display: 'flex' }}>
|
||||
<b>You are willing to give {giveLine}.</b>
|
||||
</div>
|
||||
<div style={{display: 'flex' }}>
|
||||
{ player.brick > 0 && <ResourceCounter onCount={giveCount} type='brick' max={player.brick}/> }
|
||||
{ player.wood > 0 && <ResourceCounter onCount={giveCount} type='wood' max={player.wood}/> }
|
||||
{ player.wheat > 0 && <ResourceCounter onCount={giveCount} type='wheat' max={player.wheat}/> }
|
||||
{ player.sheep > 0 && <ResourceCounter onCount={giveCount} type='sheep' max={player.sheep}/> }
|
||||
{ player.stone > 0 && <ResourceCounter onCount={giveCount} type='stone' max={player.stone}/> }
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<Button disabled={getLine === 'nothing' || giveLine === 'nothing'}
|
||||
onClick={offerClicked}>Offer</Button>
|
||||
{ isTurn && <Button onClick={cancelClicked}>cancel</Button> }
|
||||
|
37
client/src/ViewCard.css
Normal file
37
client/src/ViewCard.css
Normal file
@ -0,0 +1,37 @@
|
||||
.ViewCard {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 40vw;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: rgba(0,0,0,0.5);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.ViewCard .Title {
|
||||
align-self: center;
|
||||
padding: 2px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.ViewCard .Description {
|
||||
padding: 1em;
|
||||
max-width: 20vw;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.ViewCard > * {
|
||||
/* min-width: 40em;*/
|
||||
display: inline-flex;
|
||||
padding: 0.5em;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ViewCard .Resource {
|
||||
width: 10em; /* 5x7 aspect ratio */
|
||||
height: 14em;
|
||||
}
|
83
client/src/ViewCard.js
Normal file
83
client/src/ViewCard.js
Normal file
@ -0,0 +1,83 @@
|
||||
import React, { useState, useCallback } from "react";
|
||||
import "./ViewCard.css";
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Resource from './Resource.js';
|
||||
|
||||
const ViewCard = ({table, card}) => {
|
||||
const playCard = (event) => {
|
||||
table.playCard(card);
|
||||
}
|
||||
const close = (event) => {
|
||||
table.closeCard();
|
||||
};
|
||||
|
||||
const capitalize = (string) => {
|
||||
if (string === 'vp') {
|
||||
return 'Victory Point';
|
||||
}
|
||||
if (string === 'army') {
|
||||
return 'Knight';
|
||||
}
|
||||
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
};
|
||||
|
||||
const descriptions = {
|
||||
army: <>When played, you <b>must</b> move the robber.
|
||||
<p>Steal <b>1</b> resource card from the owner of an adjacent settlement or city.</p>
|
||||
<p>You may only play one development card during your turn -- either one
|
||||
knight or one progress card.</p></>,
|
||||
vp: <><b>1</b> victory point.
|
||||
<p>You only reveal your victory point cards when the game is over, either
|
||||
when you or an opponent reaches <b>10+</b> victory points on their turn and declares
|
||||
victory!</p></>
|
||||
};
|
||||
|
||||
let description = descriptions[card.type];
|
||||
|
||||
let canPlay = false;
|
||||
if (card.type === 'vp') {
|
||||
let points = table.game.player.points;
|
||||
table.game.player.development.forEach(item => {
|
||||
if (item.type === 'vp') {
|
||||
points++;
|
||||
}
|
||||
});
|
||||
canPlay = points >= 10;
|
||||
if (!canPlay && !card.played) {
|
||||
description = <>{description}<p>You do not have enough victory points to play this card yet.</p></>;
|
||||
}
|
||||
} else {
|
||||
canPlay = card.turn < table.game.turns;
|
||||
if (!canPlay) {
|
||||
description = <>{description}<p>You can not play this card until your next turn.</p></>;
|
||||
}
|
||||
if (canPlay) {
|
||||
canPlay = table.game.player.playedCard !== table.game.turns;
|
||||
}
|
||||
}
|
||||
|
||||
if (card.played) {
|
||||
description = <>{description}<p>You have already played this card.</p></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ViewCard">
|
||||
<Paper>
|
||||
<div className="Title">{capitalize(card.type)}</div>
|
||||
<div style={{display: 'flex', flexDirection: 'row'}}>
|
||||
<Resource type={`${card.type}-${card.card}`} disabled count={1}/>
|
||||
<div className="Description">{description}</div>
|
||||
</div>
|
||||
{ !card.played &&
|
||||
<Button disabled={!canPlay}
|
||||
onClick={playCard}>play</Button>
|
||||
}
|
||||
<Button onClick={close}>close</Button>
|
||||
</Paper>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ViewCard;
|
@ -10,6 +10,10 @@ const express = require("express"),
|
||||
const { corners } = require("./layout.js");
|
||||
const layout = require('./layout.js');
|
||||
|
||||
const MAX_SETTLEMENTS = 5;
|
||||
const MAX_CITIES = 4;
|
||||
const MAX_ROADS = 15;
|
||||
|
||||
let gameDB;
|
||||
|
||||
require("../db/games").then(function(db) {
|
||||
@ -115,14 +119,13 @@ const processTies = (players) => {
|
||||
if (A.order === B.order) {
|
||||
return B.orderRoll - A.orderRoll;
|
||||
}
|
||||
return A.order - B.order;
|
||||
return B.order - A.order;
|
||||
});
|
||||
|
||||
/* Sort the players into buckets based on their
|
||||
* order, and their current roll. If a resulting
|
||||
* roll array has more than one element, then there
|
||||
* is a tie that must be resolved */
|
||||
|
||||
let slots = [];
|
||||
players.forEach(player => {
|
||||
if (!slots[player.order]) {
|
||||
@ -135,14 +138,15 @@ const processTies = (players) => {
|
||||
});
|
||||
|
||||
let ties = false, order = 0;
|
||||
slots.forEach((slot) => {
|
||||
/* Reverse from high to low */
|
||||
slots.reverse().forEach((slot) => {
|
||||
slot.forEach(pips => {
|
||||
if (pips.length !== 1) {
|
||||
ties = true;
|
||||
pips.forEach(player => {
|
||||
player.orderRoll = 0;
|
||||
player.order = order;
|
||||
player.orderStatus = `Tied for ${order+1}.`;
|
||||
player.orderStatus = `Tied.`;
|
||||
});
|
||||
} else {
|
||||
pips[0].order = order;
|
||||
@ -258,7 +262,7 @@ const roll = (game, session) => {
|
||||
break;
|
||||
}
|
||||
|
||||
if (player.order || player.orderRoll) {
|
||||
if (player.order && player.orderRoll) {
|
||||
error = `Player ${name} has already rolled for player order.`;
|
||||
break;
|
||||
}
|
||||
@ -402,9 +406,9 @@ const processRoll = (game, dice) => {
|
||||
const getPlayer = (game, color) => {
|
||||
if (!game) {
|
||||
return {
|
||||
roads: 15,
|
||||
cities: 4,
|
||||
settlements: 5,
|
||||
roads: MAX_ROADS,
|
||||
cities: MAX_CITIES,
|
||||
settlements: MAX_SETTLEMENTS,
|
||||
points: 0,
|
||||
status: "Not active",
|
||||
lastActive: 0,
|
||||
@ -414,6 +418,7 @@ const getPlayer = (game, color) => {
|
||||
sheep: 0,
|
||||
wood: 0,
|
||||
brick: 0,
|
||||
army: 0,
|
||||
development: []
|
||||
};
|
||||
}
|
||||
@ -459,17 +464,34 @@ const loadGame = async (id) => {
|
||||
return;
|
||||
});
|
||||
|
||||
if (!game) {
|
||||
game = createGame(id);
|
||||
} else {
|
||||
if (game) {
|
||||
try {
|
||||
game = JSON.parse(game);
|
||||
console.log(`Creating backup of games/${id}`);
|
||||
await writeFile(`games/${id}.bk`, JSON.stringify(game));
|
||||
} catch (error) {
|
||||
console.error(error, game);
|
||||
return null;
|
||||
console.log(`Attempting to load backup from games/${id}.bk`);
|
||||
game = await readFile(`games/${id}.bk`)
|
||||
.catch(() => {
|
||||
console.error(error, game);
|
||||
});
|
||||
if (game) {
|
||||
try {
|
||||
game = JSON.parse(game);
|
||||
console.log(`Restoring backup to games/${id}`);
|
||||
await writeFile(`games/${id}`, JSON.stringify(game, null, 2));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
game = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!game) {
|
||||
game = createGame(id);
|
||||
}
|
||||
|
||||
if (!game.pipOrder || !game.borderOrder || !game.tileOrder) {
|
||||
console.log("Shuffling old save file");
|
||||
shuffleBoard(game);
|
||||
@ -508,6 +530,9 @@ const loadGame = async (id) => {
|
||||
if (!game.players[color].development) {
|
||||
game.players[color].development = [];
|
||||
}
|
||||
if (!game.players[color].army) {
|
||||
game.players[color].army = 0;
|
||||
}
|
||||
}
|
||||
|
||||
games[id] = game;
|
||||
@ -595,6 +620,7 @@ const adminActions = (game, action, value) => {
|
||||
name: next,
|
||||
color: getColorFromName(game, next)
|
||||
};
|
||||
game.turns++;
|
||||
addChatMessage(game, null, `The admin skipped ${name}'s turn.`);
|
||||
addChatMessage(game, null, `It is ${next}'s turn.`);
|
||||
break;
|
||||
@ -965,8 +991,7 @@ const calculateRoadLengths = (game, session) => {
|
||||
checkForTies = true;
|
||||
}
|
||||
|
||||
let longest = game.longestRoad ? game.players[game.longestRoad].roadLength : 4,
|
||||
longestPlayers = [];
|
||||
let longest = 4, longestPlayers = [];
|
||||
for (let key in game.players) {
|
||||
if (game.players[key].status === 'Not active') {
|
||||
continue;
|
||||
@ -1120,12 +1145,43 @@ const isCompatibleOffer = (player, offer) => {
|
||||
return;
|
||||
}
|
||||
valid = offer.gets.find(item =>
|
||||
item.type === give.type &&
|
||||
(item.type === give.type || item.type === 'bank') &&
|
||||
item.count === give.count) !== undefined;
|
||||
});
|
||||
return valid;
|
||||
};
|
||||
|
||||
const isSameOffer = (player, offer) => {
|
||||
const isBank = offer.name === 'The bank';
|
||||
if (isBank) {
|
||||
return false;
|
||||
}
|
||||
let same = player.gets && player.gives &&
|
||||
player.gets.length === offer.gets.length &&
|
||||
player.gives.length === offer.gives.length;
|
||||
|
||||
if (!same) {
|
||||
return false;
|
||||
}
|
||||
|
||||
player.gets.forEach(get => {
|
||||
if (!same) {
|
||||
return;
|
||||
}
|
||||
same = offer.gets.find(item =>
|
||||
item.type === get.type && item.count === get.count) !== undefined;
|
||||
});
|
||||
|
||||
if (same) player.gives.forEach(give => {
|
||||
if (!same) {
|
||||
return;
|
||||
}
|
||||
same = offer.gives.find(item =>
|
||||
item.type === give.type && item.count === give.count) !== undefined;
|
||||
});
|
||||
return same;
|
||||
};
|
||||
|
||||
const checkOffer = (player, offer) => {
|
||||
let error = undefined;
|
||||
offer.gives.forEach(give => {
|
||||
@ -1212,7 +1268,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
const name = session.name;
|
||||
let message, index;
|
||||
|
||||
let corners, corner;
|
||||
let corners, corner, card;
|
||||
|
||||
switch (action) {
|
||||
case "trade":
|
||||
@ -1229,6 +1285,11 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
}
|
||||
game.turn.actions = [ 'trade' ];
|
||||
game.turn.limits = {};
|
||||
for (let key in game.players) {
|
||||
game.players[key].gives = [];
|
||||
game.players[key].gets = [];
|
||||
delete game.players[key].offerRejected;
|
||||
}
|
||||
addChatMessage(game, session, `${name} requested to begin trading negotiations.`);
|
||||
break;
|
||||
}
|
||||
@ -1254,15 +1315,36 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
if (error) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (isSameOffer(session.player, offer)) {
|
||||
console.log(session.player);
|
||||
error = `You already have a pending offer submitted for ${offerToString(offer)}.`;
|
||||
break;
|
||||
}
|
||||
|
||||
session.player.gives = offer.gives;
|
||||
session.player.gets = offer.gets;
|
||||
|
||||
if (game.turn.name === name) {
|
||||
/* This is a new offer from the active player -- reset everyone's
|
||||
* 'offerRejected' flag */
|
||||
for (let key in game.players) {
|
||||
delete game.players[key].offerRejected;
|
||||
}
|
||||
game.turn.offer = offer;
|
||||
}
|
||||
addChatMessage(game, session, `${session.name} submitted an offer to give ${offerToString(offer)}.`);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Any player can reject an offer */
|
||||
if (value === 'reject') {
|
||||
const offer = req.body;
|
||||
session.player.offerRejected = true;
|
||||
addChatMessage(game, session, `${session.name} rejected ${game.turn.name}'s offer.`);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Only the active player can accept an offer */
|
||||
if (value === 'accept') {
|
||||
if (game.turn.name !== name) {
|
||||
@ -1273,6 +1355,11 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
const offer = req.body;
|
||||
let target;
|
||||
|
||||
error = checkOffer(session.player, offer);
|
||||
if (error) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Verify that the offer sent by the active player matches what
|
||||
* the latest offer was that was received by the requesting player */
|
||||
if (!offer.name || offer.name !== 'The bank') {
|
||||
@ -1321,6 +1408,10 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
player[item.type] -= item.count;
|
||||
});
|
||||
|
||||
addChatMessage(game, session, `${session.name} has accepted a trade ` +
|
||||
`offer for ${offerToString(session.player)} ` +
|
||||
`from ${(offer.name === 'The bank') ? 'the bank' : offer.name}.`);
|
||||
|
||||
delete game.turn.offer;
|
||||
if (target) {
|
||||
delete target.gives;
|
||||
@ -1331,8 +1422,6 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
|
||||
game.turn.actions = [];
|
||||
|
||||
addChatMessage(game, session, `${session.name} has accepted a trade ` +
|
||||
`offer from ${(offer.name === 'The bank') ? 'the bank' : offer.name}.`);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1375,6 +1464,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
name: next,
|
||||
color: getColorFromName(game, next)
|
||||
};
|
||||
game.turns++;
|
||||
addChatMessage(game, session, `${name} passed their turn.`);
|
||||
addChatMessage(game, null, `It is ${next}'s turn.`);
|
||||
break;
|
||||
@ -1444,7 +1534,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
}
|
||||
});
|
||||
if (cards.length === 0) {
|
||||
addChatMessage(game, session, `Victim did not have any cards to steal.`);
|
||||
addChatMessage(game, session, `${playerNameFromColor(game, value)} did not have any cards to steal.`);
|
||||
game.turn.actions = [];
|
||||
game.turn.limits = {};
|
||||
} else {
|
||||
@ -1473,6 +1563,12 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
error = `You cannot build until you have rolled.`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (game.turn && game.turn.roll === 7 && !game.turn.robberDone) {
|
||||
error = `Robber is in action. You can not purchase until all Robber tasks are resolved.`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (player.stone < 1 || player.wheat < 1 || player.sheep < 1) {
|
||||
error = `You have insufficient resources to purchase a development card.`;
|
||||
break;
|
||||
@ -1488,7 +1584,76 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
player.stone--;
|
||||
player.wheat--;
|
||||
player.sheep--;
|
||||
player.development.push(game.developmentCards.pop());
|
||||
card = game.developmentCards.pop();
|
||||
card.turn = game.turns;
|
||||
player.development.push(card);
|
||||
break;
|
||||
|
||||
case 'play-card':
|
||||
if (game.state !== 'normal') {
|
||||
error = `You cannot purchase a settlement 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;
|
||||
}
|
||||
if (!game.turn.roll) {
|
||||
error = `You cannot play a card until you have rolled.`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (game.turn && game.turn.roll === 7 && !game.turn.robberDone) {
|
||||
error = `Robber is in action. You can not play a card until all Robber tasks are resolved.`;
|
||||
break;
|
||||
}
|
||||
|
||||
card = req.body;
|
||||
card = player.development.find(item => item.type == card.type && item.card == card.card);
|
||||
if (!card) {
|
||||
error = `The card you want to play was not found in your hand!`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (player.playedCard === game.turns && card.type !== 'vp') {
|
||||
error = `You can only play one development card per turn!`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (card.played) {
|
||||
error = `You have already played this card.`;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if this is a victory point */
|
||||
if (card.type === 'vp') {
|
||||
let points = player.points;
|
||||
player.development.forEach(item => {
|
||||
if (item.type === 'vp') {
|
||||
points++;
|
||||
}
|
||||
});
|
||||
if (points < 10) {
|
||||
error = `You can not play victory point cards until you can reach 10!`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
card.played = true;
|
||||
player.playedCard = game.turns;
|
||||
addChatMessage(game, session, `${session.name} played a ${card.type}-${card.card} development card.`);
|
||||
|
||||
if (card.type === 'army') {
|
||||
player.army++;
|
||||
}
|
||||
|
||||
if (player.army > 2 &&
|
||||
(!game.largestArmy || game.players[game.largestArmy].army < player.army)) {
|
||||
if (game.largestArmy !== session.color) {
|
||||
game.largestArmy = session.color;
|
||||
addChatMessage(game, session, `${session.name} now has the largest army (${player.army})!`)
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'buy-settlement':
|
||||
@ -1504,6 +1669,12 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
error = `You cannot build until you have rolled.`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (game.turn && game.turn.roll === 7 && !game.turn.robberDone) {
|
||||
error = `Robber is in action. You can not purchase until all Robber tasks are resolved.`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (player.brick < 1 || player.wood < 1 || player.wheat < 1 || player.sheep < 1) {
|
||||
error = `You have insufficient resources to build a settlement.`;
|
||||
break;
|
||||
@ -1606,6 +1777,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
}
|
||||
});
|
||||
}
|
||||
player.settlements--;
|
||||
player.maritime = player.banks.map(bank => game.borders[Math.floor(bank / 3) + bank % 3]);
|
||||
game.turn.actions = ['place-road'];
|
||||
game.turn.limits = { roads: layout.corners[index].roads }; /* road placement is limited to be near this corner */
|
||||
@ -1630,6 +1802,12 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
error = `You have insufficient resources to build a city.`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (game.turn && game.turn.roll === 7 && !game.turn.robberDone) {
|
||||
error = `Robber is in action. You can not purchase until all Robber tasks are resolved.`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (player.city < 1) {
|
||||
error = `You have already built all of your cities.`;
|
||||
break;
|
||||
@ -1704,6 +1882,12 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
error = `You cannot build until you have rolled.`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (game.turn && game.turn.roll === 7 && !game.turn.robberDone) {
|
||||
error = `Robber is in action. You can not purchase until all Robber tasks are resolved.`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (player.brick < 1 || player.wood < 1) {
|
||||
error = `You have insufficient resources to build a road.`;
|
||||
break;
|
||||
@ -1792,7 +1976,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
color: getColorFromName(game, next)
|
||||
};
|
||||
calculateRoadLengths(game, session);
|
||||
addChatMessage(game, null, `It is ${next}'s turn. Place a settlement.`);
|
||||
addChatMessage(game, null, `It is ${next}'s turn to place a settlement.`);
|
||||
} else {
|
||||
game.turn = {
|
||||
actions: [],
|
||||
@ -1922,12 +2106,8 @@ const sendGame = async (req, res, game, error) => {
|
||||
/* Enforce game limit of >= 2 players */
|
||||
if (active < 2 && game.state != 'lobby' && game.state != 'invalid') {
|
||||
let message = "Insufficient players in game. Setting back to lobby."
|
||||
console.log(game);
|
||||
addChatMessage(game, null, message);
|
||||
console.log(message);
|
||||
/* It is no one's turn in the lobby */
|
||||
delete game.turn;
|
||||
game.state = 'lobby';
|
||||
resetGame(game);
|
||||
}
|
||||
game.active = active;
|
||||
|
||||
@ -1950,11 +2130,6 @@ const sendGame = async (req, res, game, error) => {
|
||||
}
|
||||
game.turn.limits.pips.push(i);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
game.turn.limits = {};
|
||||
game.turn.actions = [];
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@ -1981,6 +2156,30 @@ const sendGame = async (req, res, game, error) => {
|
||||
lastTime = message.date;
|
||||
});
|
||||
|
||||
|
||||
/* Calculate points and determine if there is a winner */
|
||||
for (let key in game.players) {
|
||||
const player = game.players[key];
|
||||
if (player.status === 'Not active') {
|
||||
continue;
|
||||
}
|
||||
player.points = 0;
|
||||
if (key === game.longestRoad) {
|
||||
player.points += 2;
|
||||
}
|
||||
if (key === game.largestArmy) {
|
||||
player.points += 2;
|
||||
}
|
||||
player.points += MAX_SETTLEMENTS - player.settlements;
|
||||
player.points += 2 * (MAX_CITIES - player.cities);
|
||||
|
||||
if (!game.winner && player.points > 10 && session.color === key) {
|
||||
addChatMessage(game, null, `${playerNameFromColor(game, key)} won the game with ${player.points} victory points!`);
|
||||
game.winner = player;
|
||||
game.state = 'winner';
|
||||
}
|
||||
}
|
||||
|
||||
/* Shallow copy game, filling its sessions with a shallow copy of sessions so we can then
|
||||
* delete the player field from them */
|
||||
const reducedGame = Object.assign({}, game, { sessions: {} }),
|
||||
@ -2003,13 +2202,25 @@ const sendGame = async (req, res, game, error) => {
|
||||
console.error(error);
|
||||
});
|
||||
|
||||
const player = session.player ? session.player : undefined;
|
||||
if (player) {
|
||||
player.haveResources = player.wheat > 0 ||
|
||||
player.brick > 0 ||
|
||||
player.sheep > 0 ||
|
||||
player.stone > 0 ||
|
||||
player.wood > 0;
|
||||
}
|
||||
|
||||
/* Strip out data that should not be shared with players */
|
||||
delete reducedGame.developmentCards;
|
||||
|
||||
const playerGame = Object.assign({}, reducedGame, {
|
||||
timestamp: Date.now(),
|
||||
status: error ? error : "success",
|
||||
name: session.name,
|
||||
color: session.color,
|
||||
order: (session.color in game.players) ? game.players[session.color].order : 0,
|
||||
player: session.player,
|
||||
player: player,
|
||||
sessions: reducedSessions,
|
||||
layout: layout
|
||||
});
|
||||
@ -2018,9 +2229,9 @@ const sendGame = async (req, res, game, error) => {
|
||||
}
|
||||
|
||||
const resetGame = (game) => {
|
||||
delete game.turn;
|
||||
|
||||
game.state = 'lobby';
|
||||
game.turns = 0;
|
||||
|
||||
game.placements = {
|
||||
corners: [],
|
||||
@ -2045,15 +2256,14 @@ const resetGame = (game) => {
|
||||
stone: 0,
|
||||
brick: 0,
|
||||
wood: 0,
|
||||
roads: 15,
|
||||
cities: 4,
|
||||
settlements: 5,
|
||||
roads: MAX_ROADS,
|
||||
cities: MAX_CITIES,
|
||||
settlements: MAX_SETTLEMENTS,
|
||||
points: 0,
|
||||
development: []
|
||||
});
|
||||
}
|
||||
|
||||
game.developmentCards = assetData.developmentCards.slice();
|
||||
shuffle(game.developmentCards);
|
||||
|
||||
for (let i = 0; i < layout.corners.length; i++) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user