1
0

Enabled House Rules: victory-points

Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
James Ketrenos 2022-03-26 21:01:11 -07:00
parent 01275059c6
commit 5a83ab5a38
5 changed files with 274 additions and 63 deletions

View File

@ -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 ||

View File

@ -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 */
}

View File

@ -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;
}

View File

@ -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>&nbsp;/&nbsp;
< 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,57 +103,134 @@ const HouseRules = ({ houseRulesActive, setHouseRulesActive }) => {
}*/
}, [setHouseRulesActive]);//ws, HouseRulesDismissed, setHouseRulesDismissed]);
if (!houseRulesActive) {
return <></>;
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]);
const setRule = (event, key) => {
console.log(event, key);
};
const rules = [ {
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 => {
item.key = item.title
.replace(/( +)|[,]/g, '-')
.toLowerCase();
const disabled = (state !== 'lobby'),
checked = houseRules && item.key in houseRules;
return <div className="HouseRule" key={item.key}>
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 checked={checked}
<Switch
inputProps={{ 'aria-label': 'controlled' }}
checked={defaultChecked}
onChange={(e) => setRule(e, item.key)}
{...{ disabled }} />
</div>
});
{ defaultChecked && item.element }
</div>
}));
}, [houseRules, setRules ]);
if (!houseRulesActive) {
return <></>;
}
return (
<div className="HouseRules">

View File

@ -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);
@ -3658,6 +3701,9 @@ router.ws("/ws/:id", async (ws, req) => {
case 'winner':
update[field] = game[field];
break;
case 'rules':
update[field] = game.houseRules ? game.houseRules : {};
break;
case 'name':
update.name = session.name;
break;
@ -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 */
};