;
+}
+
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: ,
+ }, {
+ title: `Tiles start facing down`,
+ key: `tiles-start-facing-down`,
+ description: `Flip resource tiles upside - down while placing starting settlements.`,
+ element: ,
+ }, {
+ title: `Bribery`,
+ key: `bribery`,
+ description: `Dissuade enemies from robbing you by offering resources voluntarily.`,
+ element: ,
+ }, {
+ 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: ,
+ }, {
+ title: `Everyone gets one re-roll`,
+ key: `everyone-gets-one-reroll`,
+ description: `Each player gets one chance re - roll at any point.`,
+ element: ,
+ }, {
+ title: `The Bridge`,
+ key: `the-bridge`,
+ description: `Build a super-bridge across one resource tile.`,
+ element: ,
+ }, {
+ title: `Discard desert`,
+ key: `discard-desert`,
+ description: `Scrap the desert in favour of an additional resource tile.`,
+ element: ,
+ }, {
+ title: `Roll double, roll again`,
+ key: `roll-double-roll-again`,
+ description: `Roll again if you roll two of the same number.`,
+ element: ,
+ }, {
+ title: `Robin Hood robber`,
+ key: `robin-hood-robber`,
+ description: `Robbers can't steal from players with fewer than two victory points.`,
+ element: ,
+ }, {
+ title: `Crime and Punishment`,
+ key: `crime-and-punishment`,
+ description: `Change how the robber works to make Catan more or less competitive.`,
+ element: ,
+ }, {
+ title: `Credit`,
+ key: `credit`,
+ description: `Trade with resources you don't have.`,
+ element: ,
+ } ].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
+
+
{item.title}: {item.description}
+ setRule(e, item.key)}
+ {...{ disabled }} />
+
+ { defaultChecked && item.element }
+
+ }));
+ }, [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
-
{item.title}: {item.description}
- setRule(e, item.key)}
- {...{disabled}} />
-
- });
-
return (
diff --git a/server/routes/games.js b/server/routes/games.js
index 86865fb..7005f32 100755
--- a/server/routes/games.js
+++ b/server/routes/games.js
@@ -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 */
};