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 {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
|
@ -19,6 +19,7 @@ import { Actions } from "./Actions.js";
|
||||
import { base, gamesPath } from './Common.js';
|
||||
import { GameOrder } from "./GameOrder.js";
|
||||
import { Activities } from "./Activities.js";
|
||||
import { SelectPlayer } from "./SelectPlayer.js";
|
||||
|
||||
import history from "./history.js";
|
||||
import "./App.css";
|
||||
@ -291,10 +292,10 @@ const Table = () => {
|
||||
</Paper>
|
||||
</div> }
|
||||
{ warning && <div className="WarningDialog"><Paper className="Warning">{ warning }</Paper></div> }
|
||||
{ state === 'normal' && <SelectPlayer/> }
|
||||
{ color && state === 'game-order' && <GameOrder/> }
|
||||
|
||||
<Board/>
|
||||
{ color && state === 'game-order' &&
|
||||
<GameOrder/>
|
||||
}
|
||||
|
||||
{ /* state === 'winner' &&
|
||||
<Winner color={winner}/>
|
||||
@ -311,11 +312,6 @@ const Table = () => {
|
||||
|
||||
{ isTurn && turn && turn.actions && game.turn.actions.indexOf('select-resources') !== -1 &&
|
||||
<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>
|
||||
|
@ -2,13 +2,12 @@
|
||||
display: flex;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 30vw;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
max-height: 100vh;
|
||||
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 [name, setName] = useState(game.name ? game.name : "");
|
||||
|
||||
|
@ -246,6 +246,7 @@ const roll = (game, session) => {
|
||||
return `You already rolled this turn.`;
|
||||
}
|
||||
processRoll(game, session, [ Math.ceil(Math.random() * 6), Math.ceil(Math.random() * 6) ]);
|
||||
sendUpdateToPlayers(game, { chat: game.chat });
|
||||
return;
|
||||
|
||||
default:
|
||||
@ -361,6 +362,7 @@ const processRoll = (game, session, dice) => {
|
||||
players: game.players,
|
||||
chat: game.chat
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
/* ROBBER Robber Robinson! */
|
||||
@ -1020,8 +1022,8 @@ const addChatMessage = (game, session, message) => {
|
||||
if (game.chat.length) {
|
||||
lastTime = game.chat[game.chat.length - 1].date;
|
||||
}
|
||||
if (now === lastTime) {
|
||||
now++;
|
||||
if (now <= lastTime) {
|
||||
now = lastTime + 1;
|
||||
}
|
||||
|
||||
const entry = {
|
||||
@ -1870,10 +1872,17 @@ const pass = (game, session) => {
|
||||
game.turns++;
|
||||
addActivity(game, session, `${name} passed their 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;
|
||||
robber = parseInt(robber);
|
||||
|
||||
if (game.state !== 'normal' && game.turn.roll !== 7) {
|
||||
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!`;
|
||||
}
|
||||
}
|
||||
const robber = parseInt(value ? value : 0);
|
||||
|
||||
if (game.robber === robber) {
|
||||
return `You must move the robber to a new location!`;
|
||||
}
|
||||
@ -1900,17 +1909,22 @@ const placeRobber = (game, session, value) => {
|
||||
pickRobber(game);
|
||||
addActivity(game, null, `${game.robberName} Robber Robinson entered the scene as the nefarious robber!`);
|
||||
|
||||
let colors = [];
|
||||
let targets = [];
|
||||
layout.tiles[robber].corners.forEach(cornerIndex => {
|
||||
const active = game.placements.corners[cornerIndex];
|
||||
if (active && active.color && active.color !== game.turn.color && colors.indexOf(active.color) == -1) {
|
||||
colors.push(active.color);
|
||||
if (active && 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.limits = { players: colors };
|
||||
game.turn.limits = { players: targets };
|
||||
} else {
|
||||
game.turn.actions = [];
|
||||
game.turn.robberInAction = false;
|
||||
@ -1920,18 +1934,29 @@ const placeRobber = (game, session, value) => {
|
||||
`with no other players, ` +
|
||||
`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 name = session.name;
|
||||
const stealResource = (game, session, color) => {
|
||||
if (game.turn.actions.indexOf('steal-resource') === -1) {
|
||||
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!`;
|
||||
}
|
||||
let victim = game.players[value];
|
||||
cards = [];
|
||||
const victim = game.players[color];
|
||||
const cards = [];
|
||||
[ 'wheat', 'brick', 'sheep', 'stone', 'wood' ].forEach(field => {
|
||||
for (let i = 0; i < victim[field]; i++) {
|
||||
cards.push(field);
|
||||
@ -1962,6 +1987,14 @@ const stealResource = (game, session, value) => {
|
||||
debugChat(game, 'After steal');
|
||||
|
||||
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) => {
|
||||
@ -2005,6 +2038,15 @@ const buyDevelopment = (game, session, value) => {
|
||||
card = game.developmentCards.pop();
|
||||
card.turn = game.turns;
|
||||
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 }) => {
|
||||
@ -2115,6 +2157,17 @@ const playCard = (game, session, { card }) => {
|
||||
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) => {
|
||||
@ -3344,6 +3397,27 @@ const wsConnect = async (ws, req) => {
|
||||
sendWarning(session, warning);
|
||||
}
|
||||
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:
|
||||
console.warn(`Unsupported request: ${data.type}`);
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user