Enabled House Rules: victory-points
Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
parent
01275059c6
commit
5a83ab5a38
@ -182,6 +182,8 @@ const Actions = ({
|
||||
onClick={newTableClick}>New table</Button>
|
||||
</> }
|
||||
{ name && !color && <Button disabled={color ? true : false} onClick={changeNameClick}>Change name</Button> }
|
||||
{name && color && inLobby && <Button disabled={color ? false : true}
|
||||
onClick={houseRulesClick}>House Rules</Button>}
|
||||
{ name && !inLobby && <>
|
||||
<Button disabled={
|
||||
robberActions ||
|
||||
@ -192,8 +194,8 @@ const Actions = ({
|
||||
<Button disabled={placeRoad || robberActions || !isTurn || !hasRolled || !haveResources} onClick={tradeClick}>Trade</Button>
|
||||
<Button disabled={placeRoad || robberActions || !isTurn || !hasRolled || !haveResources} onClick={buildClicked}>Build</Button>
|
||||
<Button disabled={!(turn && turn.roll === 7 && priv && priv.mustDiscard > 0)}onClick={discardClick}>Discard</Button>
|
||||
{ name && color && <Button disabled={color ? false : true}
|
||||
onClick={houseRulesClick}>House Rules</Button> }
|
||||
{name && color && <Button disabled={color ? false : true}
|
||||
onClick={houseRulesClick}>House Rules</Button>}
|
||||
<Button disabled={placeRoad || robberActions || !isTurn || !hasRolled} onClick={passClick}>Done</Button>
|
||||
</> }
|
||||
{ /* inLobby &&
|
||||
|
@ -43,6 +43,7 @@ body {
|
||||
bottom: 0;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
z-index: 60000;
|
||||
}
|
||||
|
||||
.Table .Dialogs .Dialog > div {
|
||||
@ -179,7 +180,7 @@ body {
|
||||
.Table button {
|
||||
margin: 0.25rem;
|
||||
background-color: white;
|
||||
border: 1px solid black !important;
|
||||
border: 1px solid black; /* why !important */
|
||||
}
|
||||
|
||||
.Table .MuiButton-text {
|
||||
@ -189,5 +190,5 @@ body {
|
||||
|
||||
.Table button:disabled {
|
||||
opacity: 0.5;
|
||||
border: 1px solid #ccc !important;
|
||||
border: 1px solid #ccc; /* why !important */
|
||||
}
|
@ -23,15 +23,18 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.HouseRules .HouseRule {
|
||||
.HouseRules .HouseSelector {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
.HouseRules .HouseRule .MuiSwitch-root {
|
||||
|
||||
.HouseRules .HouseRule {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.HouseRules .Title {
|
||||
@ -45,4 +48,29 @@
|
||||
margin: 0;/* 0.25rem;*/
|
||||
}
|
||||
|
||||
.HouseRules .VictoryPoints {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.HouseRules .VictoryPoints > button {
|
||||
cursor: pointer;
|
||||
padding: 0.5rem;
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1rem;
|
||||
border: 1px solid black;
|
||||
text-transform: uppercase;
|
||||
min-width: 5rem;
|
||||
}
|
||||
|
||||
.HouseRules .VictoryPoints > button:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.HouseRules .HouseRule[data-disabled="true"] button {
|
||||
border-color: #ccc;
|
||||
color: #ccc;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
@ -9,10 +9,52 @@ import "./HouseRules.css";
|
||||
|
||||
import { GlobalContext } from "./GlobalContext.js";
|
||||
|
||||
const VictoryPoints = ({ ws, houseRules, field }) => {
|
||||
const minVP = 10;
|
||||
const [points, setPoints] = useState(houseRules[field].points || minVP);
|
||||
console.log(`house-rules - ${field} - `, houseRules[field]);
|
||||
|
||||
if (!(field in houseRules)) {
|
||||
houseRules[field] = {
|
||||
points: minVP
|
||||
}
|
||||
};
|
||||
|
||||
if (houseRules[field].points && houseRules[field].points !== points) {
|
||||
setPoints(houseRules[field].points);
|
||||
}
|
||||
|
||||
const update = (value) => {
|
||||
let points = (houseRules[field].points || minVP) + value;
|
||||
if (points < minVP) {
|
||||
return;
|
||||
}
|
||||
if (points !== houseRules[field].points) {
|
||||
setPoints(points);
|
||||
houseRules[field].points = points;
|
||||
ws.send(JSON.stringify({
|
||||
type: 'rules',
|
||||
houseRules
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
return <div className="VictoryPoints">
|
||||
{points} points.
|
||||
<button onClick={() => update(+1)}>up</button> /
|
||||
< button onClick = {() => update(-1)}> down</button>
|
||||
</div>;
|
||||
}
|
||||
|
||||
const NotImplemented = () => {
|
||||
return <div>Not yet implemented.</div>;
|
||||
}
|
||||
|
||||
const HouseRules = ({ houseRulesActive, setHouseRulesActive }) => {
|
||||
const { ws } = useContext(GlobalContext);
|
||||
const [houseRules, setHouseRules] = useState(undefined);
|
||||
const [state, setState] = useState(undefined);
|
||||
const [rules, setRules] = useState([]);
|
||||
const fields = useMemo(() => [
|
||||
'state', 'rules'
|
||||
], []);
|
||||
@ -24,7 +66,9 @@ const HouseRules = ({ houseRulesActive, setHouseRulesActive }) => {
|
||||
if ('state' in data.update && data.update.state !== state) {
|
||||
setState(data.update.state);
|
||||
}
|
||||
if ('rules' in data.update && !equal(data.update.rules, rules)) {
|
||||
if ('rules' in data.update && !equal(data.update.rules, houseRules)) {
|
||||
console.log(`house-rules - setting house rules to `,
|
||||
data.update.rules);
|
||||
setHouseRules(data.update.rules);
|
||||
}
|
||||
break;
|
||||
@ -59,58 +103,135 @@ const HouseRules = ({ houseRulesActive, setHouseRulesActive }) => {
|
||||
}*/
|
||||
}, [setHouseRulesActive]);//ws, HouseRulesDismissed, setHouseRulesDismissed]);
|
||||
|
||||
console.log(`house-rules - render - `, { houseRules });
|
||||
|
||||
const setRule = useCallback((event, key) => {
|
||||
const rules = houseRules ? Object.assign({}, houseRules) : {};
|
||||
if (!(key in rules)) {
|
||||
rules[key] = { enabled: true };
|
||||
}
|
||||
rules[key].enabled = !rules[key].enabled;
|
||||
setHouseRules(rules);
|
||||
ws.send(JSON.stringify({
|
||||
type: 'rules',
|
||||
houseRules
|
||||
}));
|
||||
}, [ws, houseRules]);
|
||||
|
||||
useEffect(() => {
|
||||
setRules([ {
|
||||
title: `More victory points`,
|
||||
key: `victory-points`,
|
||||
description: `Customize how many Victory Points are required to win. ` +
|
||||
`The minimum number of Victory Points is 10.`,
|
||||
element: <VictoryPoints {...{ ws, houseRules,
|
||||
field: `victory-points` }}/>,
|
||||
}, {
|
||||
title: `Tiles start facing down`,
|
||||
key: `tiles-start-facing-down`,
|
||||
description: `Flip resource tiles upside - down while placing starting settlements.`,
|
||||
element: <NotImplemented {...{
|
||||
ws, houseRules,
|
||||
field: `tiles-start-facing-down`
|
||||
}} />,
|
||||
}, {
|
||||
title: `Bribery`,
|
||||
key: `bribery`,
|
||||
description: `Dissuade enemies from robbing you by offering resources voluntarily.`,
|
||||
element: <NotImplemented {...{
|
||||
ws, houseRules,
|
||||
field: `bribery`
|
||||
}} />,
|
||||
}, {
|
||||
title: `King of the Hill`,
|
||||
key: `king-of-the-hill`,
|
||||
description: `Keep your lead for one full turn after you reach max victory points.`,
|
||||
element: <NotImplemented {...{
|
||||
ws, houseRules,
|
||||
field: `king-of-the-hill`
|
||||
}} />,
|
||||
}, {
|
||||
title: `Everyone gets one re-roll`,
|
||||
key: `everyone-gets-one-reroll`,
|
||||
description: `Each player gets one chance re - roll at any point.`,
|
||||
element: <NotImplemented {...{
|
||||
ws, houseRules,
|
||||
field: `everyone-gets-one-reroll`
|
||||
}} />,
|
||||
}, {
|
||||
title: `The Bridge`,
|
||||
key: `the-bridge`,
|
||||
description: `Build a super-bridge across one resource tile.`,
|
||||
element: <NotImplemented {...{
|
||||
ws, houseRules,
|
||||
field: `the-bridge`
|
||||
}} />,
|
||||
}, {
|
||||
title: `Discard desert`,
|
||||
key: `discard-desert`,
|
||||
description: `Scrap the desert in favour of an additional resource tile.`,
|
||||
element: <NotImplemented {...{
|
||||
ws, houseRules,
|
||||
field: `discard-desert`
|
||||
}} />,
|
||||
}, {
|
||||
title: `Roll double, roll again`,
|
||||
key: `roll-double-roll-again`,
|
||||
description: `Roll again if you roll two of the same number.`,
|
||||
element: <NotImplemented {...{
|
||||
ws, houseRules,
|
||||
field: `roll-double-roll-again`
|
||||
}} />,
|
||||
}, {
|
||||
title: `Robin Hood robber`,
|
||||
key: `robin-hood-robber`,
|
||||
description: `Robbers can't steal from players with fewer than two victory points.`,
|
||||
element: <NotImplemented {...{
|
||||
ws, houseRules,
|
||||
field: `robin-hood-robber`
|
||||
}} />,
|
||||
}, {
|
||||
title: `Crime and Punishment`,
|
||||
key: `crime-and-punishment`,
|
||||
description: `Change how the robber works to make Catan more or less competitive.`,
|
||||
element: <NotImplemented {...{
|
||||
ws, houseRules,
|
||||
field: `crime-and-punishment`
|
||||
}} />,
|
||||
}, {
|
||||
title: `Credit`,
|
||||
key: `credit`,
|
||||
description: `Trade with resources you don't have.`,
|
||||
element: <NotImplemented {...{
|
||||
ws, houseRules,
|
||||
field: `credit`
|
||||
}} />,
|
||||
} ].map(item => {
|
||||
const disabled = (state !== 'lobby'),
|
||||
defaultChecked = houseRules
|
||||
&& (item.key in houseRules)
|
||||
? houseRules[item.key].enabled
|
||||
: false;
|
||||
console.log(`house-rules - ${item.key} - `,
|
||||
{ houseRules, defaultChecked, disabled });
|
||||
return <div className="HouseRule" data-disabled={disabled} key={item.key}>
|
||||
<div className="HouseSelector">
|
||||
<div><b>{item.title}</b>: {item.description}</div>
|
||||
<Switch
|
||||
inputProps={{ 'aria-label': 'controlled' }}
|
||||
checked={defaultChecked}
|
||||
onChange={(e) => setRule(e, item.key)}
|
||||
{...{ disabled }} />
|
||||
</div>
|
||||
{ defaultChecked && item.element }
|
||||
</div>
|
||||
}));
|
||||
}, [houseRules, setRules ]);
|
||||
|
||||
if (!houseRulesActive) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const setRule = (event, key) => {
|
||||
console.log(event, key);
|
||||
};
|
||||
|
||||
const rules = [ {
|
||||
title: `Tiles start facing down`,
|
||||
description: `Flip resource tiles upside - down while placing starting settlements.`,
|
||||
}, {
|
||||
title: `Bribery`,
|
||||
description: `Dissuade enemies from robbing you by offering resources voluntarily.`,
|
||||
}, {
|
||||
title: `King of the Hill`,
|
||||
description: `Keep your lead for one full turn after you reach max victory points.`,
|
||||
}, {
|
||||
title: `Everyone gets one re-roll`,
|
||||
description: `Each player gets one chance re - roll at any point.`,
|
||||
}, {
|
||||
title: `The Bridge`,
|
||||
description: `Build a super-bridge across one resource tile.`,
|
||||
}, {
|
||||
title: `Discard desert`,
|
||||
description: `Scrap the desert in favour of an additional resource tile.`,
|
||||
}, {
|
||||
title: `Roll double, roll again`,
|
||||
description: `Roll again if you roll two of the same number.`,
|
||||
}, {
|
||||
title: `Robin Hood robber`,
|
||||
description: `Robbers can't steal from players with fewer than two victory points.`,
|
||||
}, {
|
||||
title: `Crime and Punishment`,
|
||||
description: `Change how the robber works to make Catan more or less competitive.`,
|
||||
}, {
|
||||
title: `Credit`,
|
||||
description: `Trade with resources you don't have.`,
|
||||
} ].map(item => {
|
||||
item.key = item.title
|
||||
.replace(/( +)|[,]/g, '-')
|
||||
.toLowerCase();
|
||||
const disabled = (state !== 'lobby'),
|
||||
checked = houseRules && item.key in houseRules;
|
||||
return <div className="HouseRule" key={item.key}>
|
||||
<div><b>{item.title}</b>: {item.description}</div>
|
||||
<Switch checked={checked}
|
||||
onChange={(e) => setRule(e, item.key)}
|
||||
{...{disabled}} />
|
||||
</div>
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="HouseRules">
|
||||
<Paper>
|
||||
|
@ -2177,8 +2177,9 @@ const playCard = (game, session, card) => {
|
||||
points++;
|
||||
}
|
||||
});
|
||||
if (points < 10) {
|
||||
return `You can not play victory point cards until you can reach 10!`;
|
||||
if (points < getVictoryPointRule(game)) {
|
||||
return `You can not play victory point cards until you can reach `
|
||||
`${getVictoryPointRule(game) }!`;
|
||||
}
|
||||
addChatMessage(game, session, `${name} played a Victory Point card.`);
|
||||
}
|
||||
@ -2552,6 +2553,47 @@ const placeRoad = (game, session, index) => {
|
||||
});
|
||||
}
|
||||
|
||||
const getVictoryPointRule = (game) => {
|
||||
const minVP = 10;
|
||||
if (!('victory-points' in game.houseRules)
|
||||
|| !game.houseRules['victory-points'].enabled) {
|
||||
return minVP;
|
||||
}
|
||||
return game.houseRules['victory-pionts'].points;
|
||||
}
|
||||
|
||||
const setHouseRules = (game, session, houseRules) => {
|
||||
if (game.state !== 'lobby') {
|
||||
return `You can not modify House Rules once the game has started.`;
|
||||
}
|
||||
|
||||
for (let rule in houseRules) {
|
||||
switch (rule) {
|
||||
case 'victory-points':
|
||||
if (!('points' in houseRules[rule])) {
|
||||
return `No points specified for victory-points`;
|
||||
}
|
||||
if (!houseRules[rule].enabled) {
|
||||
addChatMessage(game, null,
|
||||
`${getName(session)} has disabled the Victory Point ` +
|
||||
`house rule.`);
|
||||
} else {
|
||||
addChatMessage(game, null,
|
||||
`${getName(session)} set the minimum Victory Points to ` +
|
||||
`${houseRules[rule].points}`);
|
||||
}
|
||||
game.houseRules[rule] = houseRules[rule];
|
||||
break;
|
||||
default:
|
||||
return `Rule ${rule} not recognized.`;
|
||||
}
|
||||
}
|
||||
sendUpdateToPlayers(game, {
|
||||
rules: game.houseRules,
|
||||
chat: game.chat
|
||||
});
|
||||
};
|
||||
|
||||
const discard = (game, session, discards) => {
|
||||
const player = session.player;
|
||||
|
||||
@ -3342,12 +3384,12 @@ const calculatePoints = (game, update) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.points < 10) {
|
||||
if (player.points < getVictoryPointRule(game)) {
|
||||
update.players = getFilteredPlayers(game);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This player has 10 points! Check if they are the current
|
||||
/* This player has enough points! Check if they are the current
|
||||
* player and if so, declare victory! */
|
||||
console.log(`${info}: Whoa! ${player.name} has ${player.points}!`);
|
||||
for (let key in game.sessions) {
|
||||
@ -3355,7 +3397,8 @@ const calculatePoints = (game, update) => {
|
||||
|| game.sessions[key].status === 'Not active') {
|
||||
continue;
|
||||
}
|
||||
const message = `Wahoo! ${player.name} has 10 points on their turn and has won!`;
|
||||
const message = `Wahoo! ${player.name} has ${player.points} `
|
||||
`points on their turn and has won!`;
|
||||
addChatMessage(game, null, message)
|
||||
console.log(`${info}: ${message}`);
|
||||
update.winner = Object.assign({}, player, {
|
||||
@ -3533,7 +3576,7 @@ router.ws("/ws/:id", async (ws, req) => {
|
||||
try {
|
||||
data = JSON.parse(message);
|
||||
} catch (error) {
|
||||
console.error(`${session.id}: parse error`, message);
|
||||
console.error(`${all}: parse error`, message);
|
||||
return;
|
||||
}
|
||||
const game = await loadGame(gameId);
|
||||
@ -3656,7 +3699,10 @@ router.ws("/ws/:id", async (ws, req) => {
|
||||
case 'turn':
|
||||
case 'turns':
|
||||
case 'winner':
|
||||
update[field] = game[field];
|
||||
update[field] = game[field];
|
||||
break;
|
||||
case 'rules':
|
||||
update[field] = game.houseRules ? game.houseRules : {};
|
||||
break;
|
||||
case 'name':
|
||||
update.name = session.name;
|
||||
@ -3878,6 +3924,14 @@ router.ws("/ws/:id", async (ws, req) => {
|
||||
sendWarning(session, warning);
|
||||
}
|
||||
break;
|
||||
case 'rules':
|
||||
console.log(`${short} - <- rules:${getName(session)} - `,
|
||||
data.houseRules);
|
||||
warning = setHouseRules(game, session, data.houseRules);
|
||||
if (warning) {
|
||||
sendWarning(session, warning);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unsupported request: ${data.type}`);
|
||||
processed = false;
|
||||
@ -4226,6 +4280,11 @@ const createGame = (id) => {
|
||||
sessions: {},
|
||||
unselected: [],
|
||||
active: 0,
|
||||
houseRules: {
|
||||
'victory-points': {
|
||||
points: 10
|
||||
}
|
||||
},
|
||||
step: 0 /* used for the suffix # in game backups */
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user