Development cards can be purchased
Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
Before Width: | Height: | Size: 155 KiB After Width: | Height: | Size: 155 KiB |
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 160 KiB |
Before Width: | Height: | Size: 162 KiB After Width: | Height: | Size: 162 KiB |
BIN
client/public/assets/gfx/card-progress-year-of-plenty.png
Normal file
After Width: | Height: | Size: 142 KiB |
@ -71,7 +71,11 @@ const Board = ({ table, game }) => {
|
||||
const Corner = ({corner}) => {
|
||||
const onClick = (event) => {
|
||||
console.log(`Corner ${corner.index}:`, game.layout.corners[corner.index]);
|
||||
table.placeSettlement(corner.index);
|
||||
if (event.currentTarget.getAttribute('data-type') === 'settlement') {
|
||||
table.placeCity(corner.index);
|
||||
} else {
|
||||
table.placeSettlement(corner.index);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
|
@ -115,10 +115,12 @@ const Placard = ({table, type, active}) => {
|
||||
};
|
||||
|
||||
const cityClicked = (event) => {
|
||||
table.buyCity();
|
||||
table.setState({ buildActive: false });
|
||||
};
|
||||
|
||||
const developmentClicked = (event) => {
|
||||
table.buyDevelopment();
|
||||
table.setState({ buildActive: false });
|
||||
};
|
||||
|
||||
@ -153,26 +155,13 @@ const Placard = ({table, type, active}) => {
|
||||
);
|
||||
};
|
||||
|
||||
class Development extends React.Component {
|
||||
render() {
|
||||
const array = [];
|
||||
for (let i = 0; i < this.props.count; i++) {
|
||||
if (this.props.type.match(/-$/)) {
|
||||
array.push(i + 1);//Math.ceil(Math.random() * this.props.max));
|
||||
} else {
|
||||
array.push("");
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div className="Stack">
|
||||
{ React.Children.map(array, i => (
|
||||
<div className="Development"
|
||||
style={{backgroundImage:`url(${assetsPath}/gfx/card-${this.props.type}${i}.png)`}}>
|
||||
</div>
|
||||
)) }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const Development = ({table, type}) => {
|
||||
return (
|
||||
<div className="Development"
|
||||
style={{
|
||||
backgroundImage:`url(${assetsPath}/gfx/card-${type}.png)`
|
||||
}}/>
|
||||
);
|
||||
};
|
||||
|
||||
const Resource = ({ type, count }) => {
|
||||
@ -466,14 +455,14 @@ const Action = ({ table }) => {
|
||||
|
||||
const inLobby = table.game.state === 'lobby',
|
||||
player = table.game ? table.game.player : undefined,
|
||||
hasRolled = table.game && table.game.turn && table.game.turn.roll,
|
||||
isTurn = table.game && table.game.turn && table.game.turn.color === table.game.color;
|
||||
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;
|
||||
|
||||
return (
|
||||
<Paper className="Action">
|
||||
{ inLobby && <>
|
||||
<StartButton table={table}/>
|
||||
<Button disabled={!table.game.color} onClick={newTableClick}>New table</Button>
|
||||
<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={!isTurn || hasRolled} onClick={rollClick}>Roll Dice</Button>
|
||||
@ -792,13 +781,25 @@ class Table extends React.Component {
|
||||
return this.sendAction('place-robber', robber);
|
||||
};
|
||||
|
||||
buyDevelopment() {
|
||||
return this.sendAction('buy-development');
|
||||
}
|
||||
|
||||
buySettlement() {
|
||||
return this.sendAction('buy-settlement');
|
||||
}
|
||||
|
||||
placeSettlement(settlement) {
|
||||
return this.sendAction('place-settlement', settlement);
|
||||
}
|
||||
|
||||
buyCity() {
|
||||
return this.sendAction('buy-city');
|
||||
}
|
||||
placeCity(city) {
|
||||
return this.sendAction('place-city', city);
|
||||
}
|
||||
|
||||
buyRoad() {
|
||||
return this.sendAction('buy-road');
|
||||
}
|
||||
@ -812,48 +813,7 @@ class Table extends React.Component {
|
||||
|
||||
throwDice() {
|
||||
return this.rollDice();
|
||||
|
||||
if (0) {
|
||||
if (this.game.state !== 'active') {
|
||||
return;
|
||||
}
|
||||
|
||||
const sum = 0;//dice[0].pips + dice[1].pips;
|
||||
if (sum === 7) { /* Robber! */
|
||||
if (this.state.total > 7) {
|
||||
let half = Math.ceil(this.state.total * 0.5);
|
||||
this.setState({ total: this.state.total - half});
|
||||
while (half) {
|
||||
switch (Math.floor(Math.random() * 5)) {
|
||||
case 0: if (this.state.wood) { this.setState({ wood: this.state.wood - 1}); half--; } break;
|
||||
case 1: if (this.state.sheep) { this.setState({ sheep: this.state.sheep - 1}); half--; } break;
|
||||
case 2: if (this.state.stone) { this.setState({ stone: this.state.stone - 1}); half--; } break;
|
||||
case 3: if (this.state.brick) { this.setState({ brick: this.state.brick - 1}); half--; } break;
|
||||
case 4:
|
||||
default: if (this.state.wheat) { this.setState({ wheat: this.state.wheat - 1}); half--; } break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.tiles.forEach((tile) => {
|
||||
if (tile.pip.roll !== sum) {
|
||||
return;
|
||||
}
|
||||
this.setState({ [tile.type]: this.state[tile.type] + 1});
|
||||
this.setState({ total: this.state.total + 1 });
|
||||
});
|
||||
}
|
||||
|
||||
this.setState({
|
||||
total: this.state.total,
|
||||
wood: this.state.wood,
|
||||
sheep: this.state.sheep,
|
||||
stone: this.state.stone,
|
||||
brick: this.state.brick,
|
||||
wheat: this.state.wheat
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
updateDimensions() {
|
||||
const hasToolbar = false;
|
||||
@ -937,15 +897,12 @@ class Table extends React.Component {
|
||||
message = <>{message}You need to roll for game order. Click <b>Roll Dice</b> below.</>;
|
||||
} else {
|
||||
message = <>{message}You rolled <Dice pips={player.order}/> for game order. Waiting for all players to roll.</>;
|
||||
message = <>{message}<br/><b>THIS IS THE END OF THE FUNCTIONALITY SO FAR</b></>;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'active':
|
||||
if (!player) {
|
||||
message = <>{message}This game is no longer in the lobby.<br/><b>TODO: Override game state to allow Lobby mode while in-game</b></>;
|
||||
} else {
|
||||
message = <>{message}<br/><b>THIS IS THE END OF THE FUNCTIONALITY SO FAR</b></>;
|
||||
}
|
||||
break;
|
||||
case null:
|
||||
@ -974,6 +931,8 @@ class Table extends React.Component {
|
||||
if (move && (this.game.turn && !this.game.turn.placedRobber)) {
|
||||
message = <>{message}<PlayerColor color={this.game.turn.color}/> {this.game.turn.name} needs to move the robber.</>
|
||||
}
|
||||
} else {
|
||||
message = <>It is <PlayerColor color={this.game.turn.color}/> {this.game.turn.name}'s turn.</>;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1075,6 +1034,20 @@ class Table extends React.Component {
|
||||
case "B": color = "blue"; break;
|
||||
case "W": color = "white"; break;
|
||||
}
|
||||
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]);
|
||||
console.log(stacks);
|
||||
development = [];
|
||||
for (let type in stacks) {
|
||||
console.log(type, stacks[type]);
|
||||
const cards = stacks[type].map(card => <Development table={this} type={`${type}-${card}`}/>);
|
||||
development.push(<div key={type} className="Stack">{ cards }</div>);
|
||||
}
|
||||
} else {
|
||||
development = <>/</>;
|
||||
}
|
||||
return (
|
||||
<div className="Table">
|
||||
|
||||
@ -1089,6 +1062,9 @@ class Table extends React.Component {
|
||||
<Resource type="brick" count={player.brick}/>
|
||||
<Resource type="sheep" count={player.sheep}/>
|
||||
</div>
|
||||
<div className="Hand">
|
||||
{ development }
|
||||
</div>
|
||||
<Placard
|
||||
active={this.state.buildActive}
|
||||
disabled={!game || !game.turn || !game.turn.roll}
|
||||
|
22
server/give
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
ADMIN=$(jq -r .admin config/local.json)
|
||||
if [[ "${ADMIN}" == "" ]]; then
|
||||
echo "You need to set your { 'admin': 'secret' } in config/local.json"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
id=$1
|
||||
give=$2
|
||||
|
||||
if [[ "${id}" == "" ]] || [[ "${give}" == "" ]]; then
|
||||
echo "Usage: give GAME-ID (wheat|wood|stone|brick|sheep)-COUNT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
curl --noproxy '*' -s -L \
|
||||
--request PUT \
|
||||
--header "PRIVATE-TOKEN: ${ADMIN}" \
|
||||
--header "Content-Type: application/json" \
|
||||
http://localhost:8930/ketr.ketran/api/v1/games/${id}/give/${give} |
|
||||
jq -r .status
|
||||
|
@ -88,18 +88,26 @@ const assetData = {
|
||||
{ left: "sheep", right: "bank" },
|
||||
{ center: "bank" }
|
||||
],
|
||||
developmentCards: []
|
||||
developmentCards: [
|
||||
]
|
||||
};
|
||||
for (let i = 0; i < 14; i++) {
|
||||
assetData.developmentCards.push("knight");
|
||||
}
|
||||
for (let i = 0; i < 6; i++) {
|
||||
assetData.developmentCards.push("progress");
|
||||
}
|
||||
for (let i = 0; i < 5; i++) {
|
||||
assetData.developmentCards.push("victoryPoint");
|
||||
for (let i = 1; i <= 14; i++) {
|
||||
assetData.developmentCards.push({
|
||||
type: 'army',
|
||||
card: i
|
||||
});
|
||||
}
|
||||
|
||||
[ 'monopoly', 'road-1', 'road-2', 'yeard-of-plenty'].forEach(card => assetData.developmentCards.push({
|
||||
type: 'progress',
|
||||
card: card
|
||||
}));
|
||||
|
||||
[ 'market', 'library', 'palace', 'university'].forEach(card => assetData.developmentCards.push({
|
||||
type: 'vp',
|
||||
card: card
|
||||
}));
|
||||
|
||||
const games = {};
|
||||
|
||||
const processTies = (players) => {
|
||||
@ -405,7 +413,8 @@ const getPlayer = (game, color) => {
|
||||
wheat: 0,
|
||||
sheep: 0,
|
||||
wood: 0,
|
||||
brick: 0
|
||||
brick: 0,
|
||||
development: []
|
||||
};
|
||||
}
|
||||
|
||||
@ -495,6 +504,12 @@ const loadGame = async (id) => {
|
||||
}
|
||||
}
|
||||
|
||||
for (let color in game.players) {
|
||||
if (!game.players[color].development) {
|
||||
game.players[color].development = [];
|
||||
}
|
||||
}
|
||||
|
||||
games[id] = game;
|
||||
return game;
|
||||
};
|
||||
@ -790,10 +805,13 @@ const getPrevPlayer = (game, name) => {
|
||||
return name;
|
||||
}
|
||||
|
||||
const getValidCorners = (game, color) => {
|
||||
const getValidCorners = (game, color, type) => {
|
||||
const limits = [];
|
||||
|
||||
/* For each corner, if the corner already has a color set, skip it
|
||||
/* For each corner, if the corner already has a color set, skip it if type
|
||||
* isn't set. If type is set, if it is a match, and the color is a match,
|
||||
* add it to the list.
|
||||
*
|
||||
* If we are limiting based on active player, a corner is only valid
|
||||
* if it connects to a road that is owned by that player.
|
||||
* If no color is set, walk each road that leaves that corner and
|
||||
@ -801,9 +819,18 @@ const getValidCorners = (game, color) => {
|
||||
* If so, this location cannot have a settlement.
|
||||
*/
|
||||
layout.corners.forEach((corner, cornerIndex) => {
|
||||
if (game.placements.corners[cornerIndex].color) {
|
||||
const placement = game.placements.corners[cornerIndex];
|
||||
if (type) {
|
||||
if (placement.color === color && placement.type === type) {
|
||||
limits.push(cornerIndex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (placement.color) {
|
||||
return;
|
||||
}
|
||||
|
||||
let valid;
|
||||
if (!color) {
|
||||
valid = true; /* Not filtering based on current player */
|
||||
@ -918,10 +945,13 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
const name = session.name;
|
||||
let message, index;
|
||||
|
||||
let corners, corner;
|
||||
|
||||
switch (action) {
|
||||
case "roll":
|
||||
error = roll(game, session);
|
||||
break;
|
||||
|
||||
case "shuffle":
|
||||
if (game.state !== "lobby") {
|
||||
error = `Game no longer in lobby (${game.state}). Can not shuffle board.`;
|
||||
@ -936,6 +966,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
console.log(message);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'pass':
|
||||
if (game.turn.name !== name) {
|
||||
error = `You cannot pass when it isn't your turn.`
|
||||
@ -957,6 +988,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
addChatMessage(game, session, `${name} passed their turn.`);
|
||||
addChatMessage(game, null, `It is ${next}'s turn.`);
|
||||
break;
|
||||
|
||||
case 'place-robber':
|
||||
if (game.state !== 'normal' && game.turn.roll !== 7) {
|
||||
error = `You cannot place robber unless 7 was rolled!`;
|
||||
@ -1004,6 +1036,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'steal-resource':
|
||||
if (game.turn.actions.indexOf('steal-resource') === -1) {
|
||||
error = `You can only steal a resource when it is valid to do so!`;
|
||||
@ -1034,6 +1067,38 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
}
|
||||
game.turn.robberDone = true;
|
||||
break;
|
||||
|
||||
case 'buy-development':
|
||||
if (game.state !== 'normal') {
|
||||
error = `You cannot purchase a development card 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 build until you have rolled.`;
|
||||
break;
|
||||
}
|
||||
if (player.stone < 1 || player.wheat < 1 || player.sheep < 1) {
|
||||
error = `You have insufficient resources to purchase a development card.`;
|
||||
break;
|
||||
}
|
||||
if (game.developmentCards.length < 1) {
|
||||
error = `There are no more development cards!`;
|
||||
break;
|
||||
}
|
||||
if (game.turn.developmentPurchased) {
|
||||
error = `You have already purchased a development card this turn.`;
|
||||
}
|
||||
addChatMessage(game, session, `Purchased a development card.`);
|
||||
player.stone--;
|
||||
player.wheat--;
|
||||
player.sheep--;
|
||||
player.development.push(game.developmentCards.pop());
|
||||
break;
|
||||
|
||||
case 'buy-settlement':
|
||||
if (game.state !== 'normal') {
|
||||
error = `You cannot purchase a settlement unless the game is active.`;
|
||||
@ -1043,6 +1108,10 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
error = `It is not your turn! It is ${game.turn.name}'s turn.`;
|
||||
break;
|
||||
}
|
||||
if (!game.turn.roll) {
|
||||
error = `You cannot build until you have rolled.`;
|
||||
break;
|
||||
}
|
||||
if (player.brick < 1 || player.wood < 1 || player.wheat < 1 || player.sheep < 1) {
|
||||
error = `You have insufficient resources to build a settlement.`;
|
||||
break;
|
||||
@ -1051,20 +1120,16 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
error = `You have already built all of your settlements.`;
|
||||
break;
|
||||
}
|
||||
let corners = getValidCorners(game, session.color);
|
||||
corners = getValidCorners(game, session.color);
|
||||
if (corners.length === 0) {
|
||||
error = `There are no valid locations for you to place a settlement.`;
|
||||
break;
|
||||
}
|
||||
player.settlements--;
|
||||
player.brick--;
|
||||
player.wood--;
|
||||
player.wheat--;
|
||||
player.sheep--;
|
||||
game.turn.actions = ['place-settlement'];
|
||||
game.turn.limits = { corners };
|
||||
addChatMessage(game, session, `Purchased a settlement. Next, they need to place it.`);
|
||||
addChatMessage(game, session, `${game.turn.name} is considering placing a settlement.`);
|
||||
break;
|
||||
|
||||
case 'place-settlement':
|
||||
if (game.state !== 'initial-placement' && game.state !== 'normal') {
|
||||
error = `You cannot place an item unless the game is active.`;
|
||||
@ -1084,14 +1149,27 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
error = `You tried to cheat! You should not try to break the rules.`;
|
||||
break;
|
||||
}
|
||||
const corner = game.placements.corners[index];
|
||||
corner = game.placements.corners[index];
|
||||
if (corner.color) {
|
||||
error = `This location already has a settlement belonging to ${playerNameFromColor(game, corner.color)}!`;
|
||||
break;
|
||||
}
|
||||
corner.color = session.color;
|
||||
corner.type = 'settlement';
|
||||
if (game.state === 'normal') {
|
||||
if (player.brick < 1 || player.wood < 1 || player.wheat < 1 || player.sheep < 1) {
|
||||
error = `You have insufficient resources to build a settlement.`;
|
||||
break;
|
||||
}
|
||||
if (player.settlements < 1) {
|
||||
error = `You have already built all of your settlements.`;
|
||||
break;
|
||||
}
|
||||
player.settlements--;
|
||||
player.brick--;
|
||||
player.wood--;
|
||||
player.wheat--;
|
||||
player.sheep--;
|
||||
corner.color = session.color;
|
||||
corner.type = 'settlement';
|
||||
game.turn.actions = [];
|
||||
game.turn.limits = {};
|
||||
addChatMessage(game, session, `${name} placed a settlement.`);
|
||||
@ -1099,11 +1177,92 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
if (game.direction && game.direction === 'backward') {
|
||||
session.initialSettlement = index;
|
||||
}
|
||||
corner.color = session.color;
|
||||
corner.type = 'settlement';
|
||||
game.turn.actions = ['place-road'];
|
||||
game.turn.limits = { roads: layout.corners[index].roads }; /* road placement is limited to be near this corner */
|
||||
addChatMessage(game, session, `Placed a settlement. Next, they need to place a road.`);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'buy-city':
|
||||
if (game.state !== 'normal') {
|
||||
error = `You cannot purchase a city 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 build until you have rolled.`;
|
||||
break;
|
||||
}
|
||||
if (player.wheat < 3 || player.stone < 2) {
|
||||
error = `You have insufficient resources to build a city.`;
|
||||
break;
|
||||
}
|
||||
if (player.city < 1) {
|
||||
error = `You have already built all of your cities.`;
|
||||
break;
|
||||
}
|
||||
corners = getValidCorners(game, session.color, 'settlement');
|
||||
if (corners.length === 0) {
|
||||
error = `There are no valid locations for you to place a city.`;
|
||||
break;
|
||||
}
|
||||
game.turn.actions = ['place-city'];
|
||||
game.turn.limits = { corners };
|
||||
addChatMessage(game, session, `${game.turn.name} is considering upgrading a settlement to a city.`);
|
||||
break;
|
||||
|
||||
case 'place-city':
|
||||
if (game.state !== 'normal') {
|
||||
error = `You cannot place an item 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;
|
||||
}
|
||||
index = parseInt(value);
|
||||
if (game.placements.corners[index] === undefined) {
|
||||
error = `You have requested to place a city illegally!`;
|
||||
break;
|
||||
}
|
||||
/* If this is not a placement the turn limits, discard it */
|
||||
if (game.turn && game.turn.limits && game.turn.limits.corners && game.turn.limits.corners.indexOf(index) === -1) {
|
||||
error = `You tried to cheat! You should not try to break the rules.`;
|
||||
break;
|
||||
}
|
||||
corner = game.placements.corners[index];
|
||||
if (corner.color !== session.color) {
|
||||
error = `This location already has a settlement belonging to ${playerNameFromColor(game, corner.color)}!`;
|
||||
break;
|
||||
}
|
||||
if (corner.type !== 'settlement') {
|
||||
error = `This location already has a city!`;
|
||||
break;
|
||||
}
|
||||
if (player.wheat < 3 || player.stone < 2) {
|
||||
error = `You have insufficient resources to build a city.`;
|
||||
break;
|
||||
}
|
||||
if (player.city < 1) {
|
||||
error = `You have already built all of your cities.`;
|
||||
break;
|
||||
}
|
||||
corner.color = session.color;
|
||||
corner.type = 'city';
|
||||
player.cities--;
|
||||
player.settlements++;
|
||||
player.wheat -= 3;
|
||||
player.stone -= 2;
|
||||
game.turn.actions = [];
|
||||
game.turn.limits = {};
|
||||
addChatMessage(game, session, `${name} upgraded a settlement to a city!`);
|
||||
break;
|
||||
|
||||
case 'buy-road':
|
||||
if (game.state !== 'normal') {
|
||||
error = `You cannot purchase a road unless the game is active.`;
|
||||
@ -1113,6 +1272,10 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
error = `It is not your turn! It is ${game.turn.name}'s turn.`;
|
||||
break;
|
||||
}
|
||||
if (!game.turn.roll) {
|
||||
error = `You cannot build until you have rolled.`;
|
||||
break;
|
||||
}
|
||||
if (player.brick < 1 || player.wood < 1) {
|
||||
error = `You have insufficient resources to build a road.`;
|
||||
break;
|
||||
@ -1126,13 +1289,11 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
error = `There are no valid locations for you to place a road.`;
|
||||
break;
|
||||
}
|
||||
player.roads--;
|
||||
player.brick--;
|
||||
player.wood--;
|
||||
game.turn.actions = ['place-road'];
|
||||
game.turn.limits = { roads };
|
||||
addChatMessage(game, session, `Purchased a road. Next, they need to place it.`);
|
||||
addChatMessage(game, session, `${game.turn.name} is considering building a road.`);
|
||||
break;
|
||||
|
||||
case 'place-road':
|
||||
if (game.state !== 'initial-placement' && game.state !== 'normal') {
|
||||
error = `You cannot place an item unless the game is active.`;
|
||||
@ -1157,13 +1318,25 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
error = `This location already has a road belonging to ${playerNameFromColor(game, road.color)}!`;
|
||||
break;
|
||||
}
|
||||
road.color = session.color;
|
||||
|
||||
if (game.state === 'normal') {
|
||||
if (player.brick < 1 || player.wood < 1) {
|
||||
error = `You have insufficient resources to build a road.`;
|
||||
break;
|
||||
}
|
||||
if (player.roads < 1) {
|
||||
error = `You have already built all of your roads.`;
|
||||
break;
|
||||
}
|
||||
player.roads--;
|
||||
player.brick--;
|
||||
player.wood--;
|
||||
road.color = session.color;
|
||||
game.turn.actions = [];
|
||||
game.turn.limits = {};
|
||||
addChatMessage(game, session, `${name} placed a road.`);
|
||||
} else if (game.state === 'initial-placement') {
|
||||
road.color = session.color;
|
||||
addChatMessage(game, session, `${name} placed a road.`);
|
||||
|
||||
let next;
|
||||
@ -1228,9 +1401,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'place-city':
|
||||
error = `City placement not yet implemented!`;
|
||||
break;
|
||||
|
||||
case 'discard':
|
||||
if (game.turn.roll !== 7) {
|
||||
error = `You can only discard due to the Robber!`;
|
||||
@ -1258,6 +1429,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
||||
addChatMessage(game, null, `${session.name} must discard ${player.mustDiscard} more cards.`);
|
||||
}
|
||||
break;
|
||||
|
||||
case "state":
|
||||
const state = value;
|
||||
if (!state) {
|
||||
@ -1568,7 +1740,7 @@ const shuffleBoard = (game) => {
|
||||
}
|
||||
}
|
||||
|
||||
shuffle(game.developmentCards)
|
||||
shuffle(game.developmentCards);
|
||||
}
|
||||
|
||||
/*
|
||||
|