Lots of fixes for volcano and other features
Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
parent
c093d7141e
commit
99f0971873
@ -140,8 +140,10 @@ const Activities = () => {
|
||||
placement = (state === 'initial-placement' || (turn && turn.active === 'road-building')),
|
||||
placeRoad = placement && turn && turn.actions && turn.actions.indexOf('place-road') !== -1,
|
||||
mustStealResource = turn && turn.actions && turn.actions.indexOf('steal-resource') !== -1,
|
||||
rollForVolcano = (isTurn && state === 'volcano'),
|
||||
rollForOrder = (state === 'game-order');
|
||||
rollForVolcano = (isTurn && state === 'volcano' && turn && !turn.select),
|
||||
rollForOrder = (state === 'game-order'),
|
||||
selectResources = turn && turn.actions && turn.actions.indexOf('select-resources') !== -1;
|
||||
|
||||
console.log(`activities - `, state, turn, activities);
|
||||
let discarders = [], mustDiscard = false;
|
||||
for (let key in players) {
|
||||
@ -161,6 +163,16 @@ console.log(`activities - `, state, turn, activities);
|
||||
});
|
||||
|
||||
let who;
|
||||
if (turn && turn.select) {
|
||||
const selecting = [];
|
||||
for (let key in turn.select) {
|
||||
selecting.push({
|
||||
color: key,
|
||||
name: color === key ? 'You' : players[key].name});
|
||||
}
|
||||
who = selecting.map((player, index) =>
|
||||
<><PlayerColor color={player.color} />{ player.name }{ index !== selecting.length - 1 ? ', ' : '' }</>);
|
||||
} else {
|
||||
if (isTurn) {
|
||||
who = 'You';
|
||||
} else {
|
||||
@ -170,6 +182,7 @@ console.log(`activities - `, state, turn, activities);
|
||||
who = <><PlayerColor color={turn.color}/> {turn.name}</>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="Activities">
|
||||
@ -194,6 +207,10 @@ console.log(`activities - `, state, turn, activities);
|
||||
<div className="Requirement">{who} must roll for Volcano devastation!</div>
|
||||
}
|
||||
|
||||
{ selectResources &&
|
||||
<div className="Requirement">{who} must select resources!</div>
|
||||
}
|
||||
|
||||
{ normalPlay && mustDiscard && <> { discarders } </> }
|
||||
|
||||
{ !isTurn && normalPlay && turn &&
|
||||
|
@ -68,10 +68,6 @@ body {
|
||||
background-color: #00000060;
|
||||
}
|
||||
|
||||
.Table .PlayersStatus {
|
||||
z-index: 5000;
|
||||
}
|
||||
|
||||
.Table .Game {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
@ -31,6 +31,17 @@ import { Dice } from "./Dice.js";
|
||||
import history from "./history.js";
|
||||
import "./App.css";
|
||||
import equal from "fast-deep-equal";
|
||||
/*
|
||||
const Pip = () => {
|
||||
<div className="Pip"
|
||||
style={{
|
||||
backgroundImage: `url(${assetsPath}/gfx/pip-numbers.png)`,
|
||||
backgroundPositionX: `${100. * (pip.order % 6) / 5.}%`,
|
||||
backgroundPositionY: `${100 * Math.floor(pip.order / 6) / 5.}%`
|
||||
}}
|
||||
><div className="Pip-Shape" /></div>
|
||||
}
|
||||
*/
|
||||
|
||||
const Table = () => {
|
||||
const params = useParams();
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React, { useEffect, useState, useContext, useRef, useMemo,
|
||||
useCallback } from "react";
|
||||
import React, { useEffect, useState, useContext, useRef, useMemo } from "react";
|
||||
import equal from "fast-deep-equal";
|
||||
import { assetsPath } from "./Common.js";
|
||||
import "./Board.css";
|
||||
@ -510,20 +509,23 @@ const Board = () => {
|
||||
const tile = Object.assign({},
|
||||
tiles[order],
|
||||
{ index: index++, left: x, top: y});
|
||||
if ('volcano' in rules
|
||||
&& rules[`volcano`].enabled
|
||||
&& tile.type === 'desert') {
|
||||
tile.type = 'volcano';
|
||||
tile.card = 0;
|
||||
}
|
||||
const volcanoActive = 'volcano' in rules
|
||||
&& rules[`volcano`].enabled;
|
||||
|
||||
if ('tiles-start-facing-down' in rules
|
||||
&& rules[`tiles-start-facing-down`].enabled
|
||||
&& state !== 'normal'
|
||||
&& state !== 'volcano'
|
||||
&& state !== 'winner') {
|
||||
&& state !== 'winner'
|
||||
&& (volcanoActive && tile.type !== 'desert')) {
|
||||
tile.type = 'jungle';
|
||||
tile.card = 0;
|
||||
}
|
||||
if (volcanoActive
|
||||
&& tile.type === 'desert') {
|
||||
tile.type = 'volcano';
|
||||
tile.card = 0;
|
||||
}
|
||||
let div = <Tile
|
||||
key={`tile-${order}`}
|
||||
tile={tile}
|
||||
|
@ -22,7 +22,6 @@
|
||||
|
||||
.ChatList .System {
|
||||
background-color: #f0f0f0;
|
||||
transform: scale(0.8);
|
||||
border-radius: 0.25em;
|
||||
}
|
||||
|
||||
@ -31,6 +30,15 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ChatList .System.MuiListItem-gutters {
|
||||
margin-bottom: 0.25rem;
|
||||
max-width: calc(100% - 0.5rem);
|
||||
}
|
||||
|
||||
.ChatList .System .MuiTypography-body1 {
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
|
||||
.ChatList .MuiListItem-gutters {
|
||||
padding: 2px 0 2px 0;
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ const Chat = () => {
|
||||
if (resource) {
|
||||
const count = resource[3] ? parseInt(resource[3]) : 1;
|
||||
message = <><Resource label={true} count={count}
|
||||
type={resource[4]}/>{resource[5]}{message}</>;
|
||||
type={resource[4]} disabled/>{resource[5]}{message}</>;
|
||||
start = resource[1];
|
||||
} else {
|
||||
message = <>{start}{message}</>;
|
||||
@ -169,7 +169,7 @@ const Chat = () => {
|
||||
<PlayerColor color={item.color}/>
|
||||
}
|
||||
<ListItemText primary={message}
|
||||
secondary={item.color && <Moment fromNow date={item.date > Date.now() ?
|
||||
secondary={item.color && <Moment fromNow trim date={item.date > Date.now() ?
|
||||
Date.now() : item.date} interval={1000}/>} />
|
||||
</ListItem>
|
||||
);
|
||||
@ -188,10 +188,11 @@ const Chat = () => {
|
||||
<TextField className="ChatInput"
|
||||
disabled={!name}
|
||||
onKeyPress={chatKeyPress}
|
||||
label={startTime !== 0 && <Moment tz={"Etc/GMT"}
|
||||
label={startTime !== 0 && <>Game duration: <Moment tz={"Etc/GMT"}
|
||||
format="h:mm:ss"
|
||||
trim
|
||||
durationFromNow interval={1000}
|
||||
date={startTime}/>}
|
||||
date={startTime}/></>}
|
||||
variant="outlined"/>
|
||||
</Paper>
|
||||
);
|
||||
|
@ -80,8 +80,6 @@ const ChooseCard = () => {
|
||||
}
|
||||
|
||||
const selectCard = useCallback((event) => {
|
||||
event.target.classList.toggle('Selected');
|
||||
|
||||
const selected = document.querySelectorAll('.ChooseCard .Selected');
|
||||
if (selected.length > count) {
|
||||
for (let i = 0; i < selected.length; i++) {
|
||||
|
@ -1,14 +1,4 @@
|
||||
|
||||
const getPlayerName = (sessions, color) => {
|
||||
for (let i = 0; i < sessions.length; i++) {
|
||||
const session = sessions[i];
|
||||
if (session.color === color) {
|
||||
return session.name;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function debounce(fn, ms) {
|
||||
let timer;
|
||||
return _ => {
|
||||
@ -25,4 +15,4 @@ const base = process.env.PUBLIC_URL;
|
||||
const assetsPath = `${base}/assets`;
|
||||
const gamesPath = `${base}`;
|
||||
|
||||
export { base, debounce, assetsPath, gamesPath, getPlayerName };
|
||||
export { base, debounce, assetsPath, gamesPath };
|
@ -11,6 +11,20 @@
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.Hand .CardsSelected {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
left: 2rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
background-color: white;
|
||||
border: 2px solid black;
|
||||
z-index: 500; /* above cards */
|
||||
pointer-events: none;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.Hand .CardGroup {
|
||||
display: flex;
|
||||
min-height: calc(7.2em + 0.5em);
|
||||
|
@ -27,6 +27,7 @@ const Hand = ({buildActive, setBuildActive, setCardActive}) => {
|
||||
const [development, setDevelopment] = useState([]);
|
||||
const [mostPorts, setMostPorts] = useState(undefined);
|
||||
const [mostDeveloped, setMostDeveloped] = useState(undefined);
|
||||
const [selected, setSelected] = useState(0);
|
||||
|
||||
const fields = useMemo(() => [
|
||||
'private', 'turn', 'color', 'longestRoad', 'largestArmy', 'mostPorts', 'mostDeveloped'
|
||||
@ -116,17 +117,34 @@ const Hand = ({buildActive, setBuildActive, setCardActive}) => {
|
||||
setDevelopment(development);
|
||||
}, [priv, setDevelopment, setCardActive]);
|
||||
|
||||
useEffect(() => {
|
||||
const count = document.querySelectorAll('.Hand .CardGroup .Selected');
|
||||
if (count.length !== selected) {
|
||||
setSelected(count.length);
|
||||
}
|
||||
}, [setSelected, selected]);
|
||||
|
||||
if (!priv) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const cardSelected = (event) => {
|
||||
const count = document.querySelectorAll('.Hand .CardGroup .Selected');
|
||||
setSelected(count.length);
|
||||
}
|
||||
|
||||
|
||||
return <div className="Hand">
|
||||
{<div className="CardsSelected"
|
||||
style={selected === 0 ? { display: 'none' } : {}}>
|
||||
{selected} cards selected
|
||||
</div>}
|
||||
<div className="CardGroup">
|
||||
<Resource type="wood" count={priv.wood}/>
|
||||
<Resource type="wheat" count={priv.wheat}/>
|
||||
<Resource type="stone" count={priv.stone}/>
|
||||
<Resource type="brick" count={priv.brick}/>
|
||||
<Resource type="sheep" count={priv.sheep}/>
|
||||
<Resource type="wood" count={priv.wood} onClick={cardSelected}/>
|
||||
<Resource type="wheat" count={priv.wheat} onClick={cardSelected} />
|
||||
<Resource type="stone" count={priv.stone} onClick={cardSelected} />
|
||||
<Resource type="brick" count={priv.brick} onClick={cardSelected} />
|
||||
<Resource type="sheep" count={priv.sheep} onClick={cardSelected} />
|
||||
</div>
|
||||
<div className="CardGroup">
|
||||
{ development }
|
||||
|
@ -19,7 +19,7 @@
|
||||
align-items: flex-start;
|
||||
pointer-events: all;
|
||||
right: auto;
|
||||
bottom: 7rem; /* 1rem over top of Resource cards in hand */
|
||||
bottom: 8rem; /* 1rem over top of Resource cards in hand */
|
||||
}
|
||||
|
||||
.PlayersStatus .Player:not(:last-child) {
|
||||
|
@ -2,19 +2,22 @@ import React from "react";
|
||||
import "./Resource.css";
|
||||
import { assetsPath } from './Common.js';
|
||||
|
||||
const Resource = ({ type, select, disabled, available, count, label, onClick }) => {
|
||||
const Resource = ({ type, disabled, available, count, label, onClick }) => {
|
||||
const array = new Array(Number(count ? count : 0));
|
||||
const click = select ? select : (event) => {
|
||||
const click = (event) => {
|
||||
if (!disabled) {
|
||||
event.target.classList.toggle('Selected');
|
||||
}
|
||||
if (onClick) {
|
||||
onClick(event);
|
||||
}
|
||||
};
|
||||
|
||||
if (label) {
|
||||
return <div className={`Resource ${count === 0 ? 'None' : ''}`}
|
||||
disabled={disabled}
|
||||
data-type={type}
|
||||
onClick={onClick ? onClick : click}
|
||||
onClick={click}
|
||||
style={{backgroundImage:`url(${assetsPath}/gfx/card-${type}.png)`}}>
|
||||
{ available !== undefined && <div className="Left">{available}</div> }
|
||||
<div className="Right">{count}</div>
|
||||
@ -29,7 +32,7 @@ const Resource = ({ type, select, disabled, available, count, label, onClick })
|
||||
<div className="Resource"
|
||||
data-type={type}
|
||||
disabled={disabled}
|
||||
onClick={onClick ? onClick : click}
|
||||
onClick={click}
|
||||
style={{backgroundImage:`url(${assetsPath}/gfx/card-${type}.png)`}}>
|
||||
</div>
|
||||
)) }
|
||||
|
@ -104,12 +104,14 @@ const Trade = () => {
|
||||
onClick={() => transfer(resource, 'get')}
|
||||
label={true}
|
||||
type={resource}
|
||||
disabled
|
||||
count={gets[resource]}/>
|
||||
<div className="Direction">{ gets[resource] === gives[resource] ? '' : (gets[resource] > gives[resource] ? <ArrowDownwardIcon/> : <ArrowUpwardIcon/>)}</div>
|
||||
<Resource
|
||||
onClick={() => transfer(resource, 'give')}
|
||||
label={true}
|
||||
type={resource}
|
||||
disabled
|
||||
available={priv ? priv[resource] - gives[resource] : undefined}
|
||||
count={gives[resource]}/>
|
||||
</div>;
|
||||
|
@ -105,7 +105,7 @@ const Winner = ({ winnerDismissed, setWinnerDismissed }) => {
|
||||
}
|
||||
const count = stats.robber.stole[type];
|
||||
robber = <>{robber}
|
||||
<Resource label={true} type={type} count={count} />
|
||||
<Resource label={true} type={type} count={count} disabled/>
|
||||
</>;
|
||||
}
|
||||
robber = <div>
|
||||
@ -137,7 +137,7 @@ const Winner = ({ winnerDismissed, setWinnerDismissed }) => {
|
||||
}
|
||||
const count = stats[player].stolen[type];
|
||||
stolen = <>{stolen}
|
||||
<Resource label={true} type={type} count={count}/>
|
||||
<Resource label={true} type={type} count={count} disabled/>
|
||||
</>;
|
||||
}
|
||||
if (stolen) {
|
||||
|
@ -391,7 +391,7 @@ const distributeResources = (game, roll) => {
|
||||
}
|
||||
|
||||
if (session) {
|
||||
addChatMessage(game, session, `${session.name} receives ${message.join(', ')}.`);
|
||||
addChatMessage(game, session, `${session.name} receives ${message.join(', ')} for pip ${roll}.`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -476,7 +476,6 @@ const processRoll = (game, session, dice) => {
|
||||
game.turn.select = {};
|
||||
const volcano = layout.tiles.find((tile, index) =>
|
||||
staticData.tiles[game.tileOrder[index]].type === 'desert');
|
||||
console.log({ mode: 'gold', volcano });
|
||||
volcano.corners.forEach(index => {
|
||||
const corner = game.placements.corners[index];
|
||||
if (corner.color) {
|
||||
@ -488,9 +487,11 @@ const processRoll = (game, session, dice) => {
|
||||
count += corner.type === 'settlement' ? 1 : 2;
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`Volcano! - `, {
|
||||
mode: 'gold',
|
||||
selected: game.turn.select
|
||||
});
|
||||
if (count) {
|
||||
game.turn.actions = [ 'select-resources' ];
|
||||
/* To gain volcano resources, you need at least 3 settlements,
|
||||
* so Robin Hood Robber does not apply */
|
||||
if (volcano === layout.tiles[game.robber]) {
|
||||
@ -499,6 +500,7 @@ const processRoll = (game, session, dice) => {
|
||||
delete game.turn.select;
|
||||
} else {
|
||||
addChatMessage(game, null, `House rule 'Volcanoes have minerals' activated. Players must select which resources to receive from the Volcano!`);
|
||||
game.turn.actions = ['select-resources'];
|
||||
game.turn.active = 'volcano';
|
||||
}
|
||||
} else {
|
||||
@ -521,7 +523,8 @@ const processRoll = (game, session, dice) => {
|
||||
turn: game.turn,
|
||||
players: getFilteredPlayers(game),
|
||||
chat: game.chat,
|
||||
dice: game.dice
|
||||
dice: game.dice,
|
||||
state: game.state
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -804,11 +807,10 @@ const adminActions = (game, action, value, query) => {
|
||||
if (session.player.cities === 0) {
|
||||
return `Player ${game.turn.name} does not have any more cities to give.`;
|
||||
}
|
||||
corners = getValidCorners(game, session.color);
|
||||
corners = getValidCorners(game, session.color, 'settlement');
|
||||
if (corners.length === 0) {
|
||||
return `There are no valid locations for ${game.turn.name} to place a settlement.`;
|
||||
}
|
||||
corners = getValidCorners(game, session.color, 'settlement');
|
||||
game.turn.free = true;
|
||||
setForCityPlacement(game, corners);
|
||||
addChatMessage(game, null, `Admin gave a city to ${game.turn.name}. ` +
|
||||
@ -2766,7 +2768,7 @@ const placeRoad = (game, session, index) => {
|
||||
});
|
||||
message.push(`${receives[type]} ${type}`);
|
||||
}
|
||||
addChatMessage(game, session, `${session.name} receives ${message.join(', ')}.`);
|
||||
addChatMessage(game, session, `${session.name} receives ${message.join(', ')} for initial settlement placement.`);
|
||||
}
|
||||
}
|
||||
addChatMessage(game, null, `It is ${session.name}'s turn.`);
|
||||
@ -3005,6 +3007,7 @@ const selectResources = (game, session, cards) => {
|
||||
count = 1;
|
||||
}
|
||||
if (game.state === 'volcano') {
|
||||
console.log({ cards, turn: game.turn });
|
||||
if (!game.turn.select) {
|
||||
count = 0;
|
||||
} else if (session.color in game.turn.select) {
|
||||
@ -3052,8 +3055,6 @@ const selectResources = (game, session, cards) => {
|
||||
display.push(`${selected[card]} ${card}`);
|
||||
}
|
||||
|
||||
addActivity(game, session, `${session.name} has chosen ${display.join(', ')}!`);
|
||||
|
||||
switch (game.turn.active) {
|
||||
case 'monopoly':
|
||||
const gave = [], type = cards[0];
|
||||
@ -3084,10 +3085,11 @@ const selectResources = (game, session, cards) => {
|
||||
}
|
||||
|
||||
if (gave.length) {
|
||||
addChatMessage(game, session, `${session.name} player Monopoly and selected ${display.join(', ')}. ` +
|
||||
addChatMessage(game, session, `${session.name} played Monopoly and selected ${display.join(', ')}. ` +
|
||||
`Players ${gave.join(', ')}. In total, they received ${total} ${type}.`);
|
||||
} else {
|
||||
addActivity(game, session, 'No players had that resource. Wa-waaaa.');
|
||||
|
||||
addActivity(game, session, `${session.name} has chosen ${display.join(', ')}! Unfortunately, no players had that resource. Wa-waaaa.`);
|
||||
}
|
||||
delete game.turn.active;
|
||||
game.turn.actions = [];
|
||||
@ -4039,6 +4041,25 @@ router.ws("/ws/:id", async (ws, req) => {
|
||||
case 'turn':
|
||||
case 'turns':
|
||||
case 'winner':
|
||||
case 'placements':
|
||||
case 'longestRoadLength':
|
||||
case 'robber':
|
||||
case 'robberName':
|
||||
case 'pips':
|
||||
case 'pipsOrder':
|
||||
case 'borders':
|
||||
case 'tileOrder':
|
||||
case 'active':
|
||||
case 'largestArmy':
|
||||
case 'mostDeveloped':
|
||||
case 'mostPorts':
|
||||
case 'longestRoad':
|
||||
case 'tiles':
|
||||
case 'pipOrder':
|
||||
case 'signature':
|
||||
case 'borderOrder':
|
||||
case 'dice':
|
||||
case 'activities':
|
||||
update[field] = game[field];
|
||||
break;
|
||||
case 'rules':
|
||||
|
Loading…
x
Reference in New Issue
Block a user