Implemented place-robber, pass, and steal-resource. Added SelectPlayer.
Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
parent
9633e48f21
commit
d01ab17e13
@ -60,6 +60,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.Table .Game {
|
.Table .Game {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
@ -19,6 +19,7 @@ import { Actions } from "./Actions.js";
|
|||||||
import { base, gamesPath } from './Common.js';
|
import { base, gamesPath } from './Common.js';
|
||||||
import { GameOrder } from "./GameOrder.js";
|
import { GameOrder } from "./GameOrder.js";
|
||||||
import { Activities } from "./Activities.js";
|
import { Activities } from "./Activities.js";
|
||||||
|
import { SelectPlayer } from "./SelectPlayer.js";
|
||||||
|
|
||||||
import history from "./history.js";
|
import history from "./history.js";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
@ -291,10 +292,10 @@ const Table = () => {
|
|||||||
</Paper>
|
</Paper>
|
||||||
</div> }
|
</div> }
|
||||||
{ warning && <div className="WarningDialog"><Paper className="Warning">{ warning }</Paper></div> }
|
{ warning && <div className="WarningDialog"><Paper className="Warning">{ warning }</Paper></div> }
|
||||||
|
{ state === 'normal' && <SelectPlayer/> }
|
||||||
|
{ color && state === 'game-order' && <GameOrder/> }
|
||||||
|
|
||||||
<Board/>
|
<Board/>
|
||||||
{ color && state === 'game-order' &&
|
|
||||||
<GameOrder/>
|
|
||||||
}
|
|
||||||
|
|
||||||
{ /* state === 'winner' &&
|
{ /* state === 'winner' &&
|
||||||
<Winner color={winner}/>
|
<Winner color={winner}/>
|
||||||
@ -311,12 +312,7 @@ const Table = () => {
|
|||||||
|
|
||||||
{ isTurn && turn && turn.actions && game.turn.actions.indexOf('select-resources') !== -1 &&
|
{ isTurn && turn && turn.actions && game.turn.actions.indexOf('select-resources') !== -1 &&
|
||||||
<ChooseCard type={turn.active}/>
|
<ChooseCard type={turn.active}/>
|
||||||
}
|
*/ }
|
||||||
|
|
||||||
{ game.state === 'normal' &&
|
|
||||||
turn && isTurn && turn.actions && turn.actions.indexOf('steal-resource') !== -1 &&
|
|
||||||
<SelectPlayer table={this} game={this.state} players={game.turn.limits.players}/>
|
|
||||||
*/ }
|
|
||||||
|
|
||||||
<div className="Hand">todo: player's hand</div>
|
<div className="Hand">todo: player's hand</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,13 +2,12 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 30vw;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
max-height: 100vh;
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
53
client/src/SelectPlayer.css
Normal file
53
client/src/SelectPlayer.css
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
.SelectPlayer {
|
||||||
|
display: flex;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
top: 0;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
overflow: auto;
|
||||||
|
background-color: #40404020;
|
||||||
|
z-index: 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SelectPlayer .Title {
|
||||||
|
align-self: center;
|
||||||
|
padding: 2px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SelectPlayer .SelectPlayerList {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
padding: 0.5em;
|
||||||
|
background-color:rgba(224, 224, 224);
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SelectPlayer > * {
|
||||||
|
width: 20em;
|
||||||
|
display: inline-flex;
|
||||||
|
padding: 0.5em;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SelectPlayer .PlayerColor {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SelectPlayer .SelectPlayerItem {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
padding: 2px 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SelectPlayer > * {
|
||||||
|
margin: 0 0.25em;
|
||||||
|
}
|
84
client/src/SelectPlayer.js
Normal file
84
client/src/SelectPlayer.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import React, { useState, useEffect, useContext, useRef, useMemo } from "react";
|
||||||
|
import Paper from '@material-ui/core/Paper';
|
||||||
|
import equal from "fast-deep-equal";
|
||||||
|
|
||||||
|
import { PlayerColor } from "./PlayerColor.js";
|
||||||
|
|
||||||
|
import "./SelectPlayer.css";
|
||||||
|
|
||||||
|
import { GlobalContext } from "./GlobalContext.js";
|
||||||
|
|
||||||
|
const SelectPlayer = () => {
|
||||||
|
const { ws } = useContext(GlobalContext);
|
||||||
|
const [turn, setTurn] = useState(undefined);
|
||||||
|
const [color, setColor] = useState(undefined);
|
||||||
|
const fields = useMemo(() => [
|
||||||
|
'turn', 'color'
|
||||||
|
], []);
|
||||||
|
|
||||||
|
const onWsMessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
switch (data.type) {
|
||||||
|
case 'game-update':
|
||||||
|
console.log(`select-players - game-update: `, data.update);
|
||||||
|
if ('turn' in data.update && !equal(turn, data.update.turn)) {
|
||||||
|
setTurn(data.update.turn);
|
||||||
|
}
|
||||||
|
if ('color' in data.update && data.update.color !== color) {
|
||||||
|
setColor(data.update.color);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const refWsMessage = useRef(onWsMessage);
|
||||||
|
useEffect(() => { refWsMessage.current = onWsMessage; });
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ws) { return; }
|
||||||
|
const cbMessage = e => refWsMessage.current(e);
|
||||||
|
ws.addEventListener('message', cbMessage);
|
||||||
|
return () => { ws.removeEventListener('message', cbMessage); }
|
||||||
|
}, [ws, refWsMessage]);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ws) { return; }
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
type: 'get',
|
||||||
|
fields
|
||||||
|
}));
|
||||||
|
}, [ws, fields]);
|
||||||
|
|
||||||
|
const playerClick = (event) => {
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
type: 'steal-resource',
|
||||||
|
color: event.currentTarget.getAttribute('data-color')
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!color || !turn || turn.color !== color || !turn.limits || !turn.limits.players) {
|
||||||
|
return (<></>);
|
||||||
|
}
|
||||||
|
|
||||||
|
const list = turn.limits.players.map(item =>
|
||||||
|
<div className="SelectPlayerItem"
|
||||||
|
onClick={playerClick}
|
||||||
|
data-color={item.color}
|
||||||
|
key={`player-${item.color}`}>
|
||||||
|
<PlayerColor color={item.color}/>
|
||||||
|
<div>{item.name}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="SelectPlayer">
|
||||||
|
<Paper>
|
||||||
|
<div className="Title">Select Player to Steal From</div>
|
||||||
|
<div className="SelectPlayerList">
|
||||||
|
{ list }
|
||||||
|
</div>
|
||||||
|
</Paper>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { SelectPlayer };
|
@ -67,41 +67,6 @@ const StartButton = ({ table, game }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const SelectPlayer = ({table, game, players}) => {
|
|
||||||
const playerClick = (event) => {
|
|
||||||
table.stealResource(event.currentTarget.getAttribute('data-color'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!game.id) {
|
|
||||||
return (<></>);
|
|
||||||
}
|
|
||||||
|
|
||||||
let list = players.map(color => {
|
|
||||||
let item = {
|
|
||||||
color: color,
|
|
||||||
name: getPlayerName(game.sessions, color)
|
|
||||||
};
|
|
||||||
return <div className="SelectPlayerItem"
|
|
||||||
onClick={playerClick}
|
|
||||||
data-color={color}
|
|
||||||
key={`player-${item.color}`}>
|
|
||||||
<PlayerColor color={item.color}/>
|
|
||||||
<div>{item.name}</div>
|
|
||||||
</div>;
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="SelectPlayer">
|
|
||||||
{ game && <Paper>
|
|
||||||
<div className="Title">Select Player to Steal From</div>
|
|
||||||
<div className="SelectPlayerList">
|
|
||||||
{ list }
|
|
||||||
</div>
|
|
||||||
</Paper> }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const PlayerName = ({table, game}) => {
|
const PlayerName = ({table, game}) => {
|
||||||
const [name, setName] = useState(game.name ? game.name : "");
|
const [name, setName] = useState(game.name ? game.name : "");
|
||||||
|
|
||||||
|
@ -246,6 +246,7 @@ const roll = (game, session) => {
|
|||||||
return `You already rolled this turn.`;
|
return `You already rolled this turn.`;
|
||||||
}
|
}
|
||||||
processRoll(game, session, [ Math.ceil(Math.random() * 6), Math.ceil(Math.random() * 6) ]);
|
processRoll(game, session, [ Math.ceil(Math.random() * 6), Math.ceil(Math.random() * 6) ]);
|
||||||
|
sendUpdateToPlayers(game, { chat: game.chat });
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -361,6 +362,7 @@ const processRoll = (game, session, dice) => {
|
|||||||
players: game.players,
|
players: game.players,
|
||||||
chat: game.chat
|
chat: game.chat
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ROBBER Robber Robinson! */
|
/* ROBBER Robber Robinson! */
|
||||||
@ -1020,8 +1022,8 @@ const addChatMessage = (game, session, message) => {
|
|||||||
if (game.chat.length) {
|
if (game.chat.length) {
|
||||||
lastTime = game.chat[game.chat.length - 1].date;
|
lastTime = game.chat[game.chat.length - 1].date;
|
||||||
}
|
}
|
||||||
if (now === lastTime) {
|
if (now <= lastTime) {
|
||||||
now++;
|
now = lastTime + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const entry = {
|
const entry = {
|
||||||
@ -1870,10 +1872,17 @@ const pass = (game, session) => {
|
|||||||
game.turns++;
|
game.turns++;
|
||||||
addActivity(game, session, `${name} passed their turn.`);
|
addActivity(game, session, `${name} passed their turn.`);
|
||||||
addChatMessage(game, null, `It is ${next}'s turn.`);
|
addChatMessage(game, null, `It is ${next}'s turn.`);
|
||||||
|
|
||||||
|
sendUpdateToPlayers(game, {
|
||||||
|
turn: game.turn,
|
||||||
|
chat: game.chat,
|
||||||
|
activites: game.activities
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const placeRobber = (game, session, value) => {
|
const placeRobber = (game, session, robber) => {
|
||||||
const name = session.name;
|
const name = session.name;
|
||||||
|
robber = parseInt(robber);
|
||||||
|
|
||||||
if (game.state !== 'normal' && game.turn.roll !== 7) {
|
if (game.state !== 'normal' && game.turn.roll !== 7) {
|
||||||
return `You cannot place robber unless 7 was rolled!`;
|
return `You cannot place robber unless 7 was rolled!`;
|
||||||
@ -1890,7 +1899,7 @@ const placeRobber = (game, session, value) => {
|
|||||||
return `You cannot place the robber until everyone has discarded!`;
|
return `You cannot place the robber until everyone has discarded!`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const robber = parseInt(value ? value : 0);
|
|
||||||
if (game.robber === robber) {
|
if (game.robber === robber) {
|
||||||
return `You must move the robber to a new location!`;
|
return `You must move the robber to a new location!`;
|
||||||
}
|
}
|
||||||
@ -1900,17 +1909,22 @@ const placeRobber = (game, session, value) => {
|
|||||||
pickRobber(game);
|
pickRobber(game);
|
||||||
addActivity(game, null, `${game.robberName} Robber Robinson entered the scene as the nefarious robber!`);
|
addActivity(game, null, `${game.robberName} Robber Robinson entered the scene as the nefarious robber!`);
|
||||||
|
|
||||||
let colors = [];
|
let targets = [];
|
||||||
layout.tiles[robber].corners.forEach(cornerIndex => {
|
layout.tiles[robber].corners.forEach(cornerIndex => {
|
||||||
const active = game.placements.corners[cornerIndex];
|
const active = game.placements.corners[cornerIndex];
|
||||||
if (active && active.color && active.color !== game.turn.color && colors.indexOf(active.color) == -1) {
|
if (active && active.color
|
||||||
colors.push(active.color);
|
&& active.color !== game.turn.color
|
||||||
|
&& targets.findIndex(item => item.color === active.color) === -1) {
|
||||||
|
targets.push({
|
||||||
|
color: active.color,
|
||||||
|
name: game.players[active.color].name
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (colors.length) {
|
if (targets.length) {
|
||||||
game.turn.actions = [ 'steal-resource' ],
|
game.turn.actions = [ 'steal-resource' ],
|
||||||
game.turn.limits = { players: colors };
|
game.turn.limits = { players: targets };
|
||||||
} else {
|
} else {
|
||||||
game.turn.actions = [];
|
game.turn.actions = [];
|
||||||
game.turn.robberInAction = false;
|
game.turn.robberInAction = false;
|
||||||
@ -1920,18 +1934,29 @@ const placeRobber = (game, session, value) => {
|
|||||||
`with no other players, ` +
|
`with no other players, ` +
|
||||||
`so ${game.turn.name} does not steal resources from anyone.`);
|
`so ${game.turn.name} does not steal resources from anyone.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendUpdateToPlayers(game, {
|
||||||
|
placements: game.placements,
|
||||||
|
turn: game.turn,
|
||||||
|
chat: game.chat,
|
||||||
|
robber: game.robber,
|
||||||
|
robberName: game.robberName,
|
||||||
|
activities: game.activities
|
||||||
|
});
|
||||||
|
sendUpdateToPlayer(session, {
|
||||||
|
private: game.player
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const stealResource = (game, session, value) => {
|
const stealResource = (game, session, color) => {
|
||||||
const name = session.name;
|
|
||||||
if (game.turn.actions.indexOf('steal-resource') === -1) {
|
if (game.turn.actions.indexOf('steal-resource') === -1) {
|
||||||
return `You can only steal a resource when it is valid to do so!`;
|
return `You can only steal a resource when it is valid to do so!`;
|
||||||
}
|
}
|
||||||
if (game.turn.limits.players.indexOf(value) === -1) {
|
if (game.turn.limits.players.findIndex(item => item.color === color) === -1) {
|
||||||
return `You can only steal a resource from a player on this terrain!`;
|
return `You can only steal a resource from a player on this terrain!`;
|
||||||
}
|
}
|
||||||
let victim = game.players[value];
|
const victim = game.players[color];
|
||||||
cards = [];
|
const cards = [];
|
||||||
[ 'wheat', 'brick', 'sheep', 'stone', 'wood' ].forEach(field => {
|
[ 'wheat', 'brick', 'sheep', 'stone', 'wood' ].forEach(field => {
|
||||||
for (let i = 0; i < victim[field]; i++) {
|
for (let i = 0; i < victim[field]; i++) {
|
||||||
cards.push(field);
|
cards.push(field);
|
||||||
@ -1962,6 +1987,14 @@ const stealResource = (game, session, value) => {
|
|||||||
debugChat(game, 'After steal');
|
debugChat(game, 'After steal');
|
||||||
|
|
||||||
game.turn.robberInAction = false;
|
game.turn.robberInAction = false;
|
||||||
|
sendUpdateToPlayers(game, {
|
||||||
|
turn: game.turn,
|
||||||
|
chat: game.chat,
|
||||||
|
activities: game.activities
|
||||||
|
});
|
||||||
|
sendUpdateToPlayer(session, {
|
||||||
|
private: game.player
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const buyDevelopment = (game, session, value) => {
|
const buyDevelopment = (game, session, value) => {
|
||||||
@ -2005,6 +2038,15 @@ const buyDevelopment = (game, session, value) => {
|
|||||||
card = game.developmentCards.pop();
|
card = game.developmentCards.pop();
|
||||||
card.turn = game.turns;
|
card.turn = game.turns;
|
||||||
player.development.push(card);
|
player.development.push(card);
|
||||||
|
|
||||||
|
sendUpdateToPlayers(game, {
|
||||||
|
chat: game.chat,
|
||||||
|
activities: game.activities,
|
||||||
|
players: getFilteredPlayers(game)
|
||||||
|
});
|
||||||
|
sendUpdateToPlayer(session, {
|
||||||
|
private: game.player
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const playCard = (game, session, { card }) => {
|
const playCard = (game, session, { card }) => {
|
||||||
@ -2115,6 +2157,17 @@ const playCard = (game, session, { card }) => {
|
|||||||
game.turn.limits.pips.push(i);
|
game.turn.limits.pips.push(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendUpdateToPlayers(game, {
|
||||||
|
chat: game.chat,
|
||||||
|
activities: game.activities,
|
||||||
|
largestArmy: game.largestArmy,
|
||||||
|
largestArmySize: game.largestArmySize,
|
||||||
|
turn: game.turn
|
||||||
|
});
|
||||||
|
sendUpdateToPlayer(session, {
|
||||||
|
private: game.player
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const placeSettlement = (game, session, index) => {
|
const placeSettlement = (game, session, index) => {
|
||||||
@ -3344,6 +3397,27 @@ const wsConnect = async (ws, req) => {
|
|||||||
sendWarning(session, warning);
|
sendWarning(session, warning);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'place-robber':
|
||||||
|
console.log(`${short}: <- place-robber:${getName(session)} ${data.index}`);
|
||||||
|
warning = placeRobber(game, session, data.index);
|
||||||
|
if (warning) {
|
||||||
|
sendWarning(session, warning);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'steal-resource':
|
||||||
|
console.log(`${short}: <- steal-resource:${getName(session)} ${data.color}`);
|
||||||
|
warning = stealResource(game, session, data.color);
|
||||||
|
if (warning) {
|
||||||
|
sendWarning(session, warning);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'pass':
|
||||||
|
console.log(`${short}: <- pass:${getName(session)}`);
|
||||||
|
warning = pass(game, session);
|
||||||
|
if (warning) {
|
||||||
|
sendWarning(session, warning);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.warn(`Unsupported request: ${data.type}`);
|
console.warn(`Unsupported request: ${data.type}`);
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user