@@ -626,28 +891,128 @@ function renderNewGameModal() {
`;
}
+function renderWeatherDraftModal() {
+ if (state.phase !== "weather" || !state.weatherDraft) {
+ return "";
+ }
+
+ const draft = state.weatherDraft;
+ const currentPlayer = getCurrentWeatherDraftPlayer();
+
+ return `
+
+
+
+
Round ${state.round}
+
Weather Draft
+
+
+
+
${currentPlayer?.name ?? "A player"} must draft one card for this round or ban one to deny it.
+
+ ☀ Draft: apply to the board for 1 round
+ ✕ Ban: remove it this round
+
+
+ ${getOrderedPlayers(draft.playerOrder).map((player, index) => `${player.name}`).join("")}
+
+
+
+ ${draft.row.map((cardId) => {
+ const card = getWeatherCard(cardId);
+ const drafted = draft.drafted.includes(cardId);
+ const banned = draft.banned.includes(cardId);
+ const available = !drafted && !banned;
+ return `
+
+
+
${drafted ? "Drafted" : banned ? "Banned" : "Open"}
+
${card?.title ?? cardId}
+
${card?.description ?? ""}
+
+ ${available ? `
+
+
+
+
+ ` : ""}
+
+ `;
+ }).join("")}
+
+
+ `;
+}
+
+function renderInitiativeModal() {
+ if (state.phase !== "initiative" || !state.initiativeDraft) {
+ return "";
+ }
+
+ const draft = state.initiativeDraft;
+ const currentBidder = getCurrentBiddingPlayer();
+ const orderedBidders = getOrderedPlayers(draft.biddingOrder);
+
+ return `
+
+
+
+
Round ${state.round}
+
Initiative Draft
+
+
+
+
${currentBidder?.name ?? "A player"} chooses a seat. Earlier seats gain extra growth before the round begins.
+
+ ${orderedBidders.map((player, index) => `${player.name}`).join("")}
+
+
+
+ ${draft.seatAssignments.map((playerId, seatIndex) => {
+ const assignedPlayer = playerId === null ? null : state.players[playerId];
+ const bonus = draft.seatBonuses[seatIndex] ?? 0;
+ const disabled = playerId !== null ? "disabled" : "";
+ return `
+
+ `;
+ }).join("")}
+
+
+ `;
+}
+
function renderScoreboard() {
+ const liveExposureScores = getLiveExposureScores();
return state.players.map((player, index) => {
- const isActive = index === state.activePlayerId && !state.gameOver;
+ const isActive = player.id === state.activePlayerId && !state.gameOver;
+ const seatIndex = state.turnOrder.indexOf(player.id);
const previous = previousScoreSnapshot?.[index];
- const totalChanged = previous && previous.totalScore !== player.totalScore;
- const sunlightChanged = previous && previous.roundScore !== player.roundScore;
+ const sunlightChanged = previous && previous.currentExposure !== liveExposureScores[index];
const growthChanged = previous && previous.growthPoints !== player.growthPoints;
const bankChanged = previous && previous.bankedPoints !== player.bankedPoints;
return `
-
-
${player.name}
+
+
+
${player.name}
+
+
Lifetime ${player.lifetimeGrowthIncome}
- Total
- ${player.totalScore}
-
-
- Sunlight
- ${player.roundScore}
+ Current
+ ${liveExposureScores[index]}
Energy
@@ -658,6 +1023,9 @@ function renderScoreboard() {
${player.bankedPoints}
+
`;
}).join("");
@@ -826,6 +1194,13 @@ function renderSidebar() {
const player = getCurrentPlayer();
const rootShiftMoves = getSelectedRootShiftMoves();
const boardLocked = isInteractionLocked();
+ const turnOrderSummary = getOrderedPlayers(state.turnOrder).map((orderedPlayer, index) => `${index + 1}. ${orderedPlayer.name}`).join(" | ");
+ const activeEffectsMarkup = state.activeRoundEffects.length > 0
+ ? `
${state.activeRoundEffects.map((cardId) => {
+ const card = getWeatherCard(cardId);
+ return `
${card?.title ?? cardId}
`;
+ }).join("")}
`
+ : `
No weather effects active.
`;
const nextGrowthText = state.roundSummary
? state.players.map((current) => `${current.name}: ${current.growthPoints}`).join(" | ")
: "Next round growth = 1 + columns owned + any banked growth.";
@@ -842,22 +1217,24 @@ function renderSidebar() {
Round ${state.round}
-
${state.gameOver ? "Game Over" : `${player.name}'s turn`}
-
${state.gameOver ? "Tallies are final." : "Spend growth by extending upward. Vertical costs 1. Diagonal costs 2. Click a glowing new node to undo back to that point before you commit the turn."}
+
${getTurnLabel()}
+
${state.phase === "initiative" ? "Choose a public seat for this round. Earlier seats gain more growth, later seats act later." : state.gameOver ? "Tallies are final." : "Spend growth by extending upward. Vertical costs 1. Diagonal costs 2. Click a glowing new node to undo back to that point before you commit the turn."}
${!state.gameOver ? `
${state.turnMoves.length} pending move${state.turnMoves.length === 1 ? "" : "s"} this turn. ${player.bankedPoints} banked for the next round.
` : ""}
${state.round === 1 ? `
Select a root on the bottom row to shift it left or right for ${ROOT_SHIFT_COST} point during round 1.
` : ""}
+
Turn order: ${turnOrderSummary}
+
${getWinConditionSummary()}
${rootShiftMoves.length > 0 ? `
${rootShiftMoves.map((move) => ``).join("")}
` : ""}
-
Round economy
${nextGrowthText}
+ ${activeEffectsMarkup}
${state.roundSummary?.event ? `${state.roundSummary.event}
` : ""}
@@ -867,6 +1244,10 @@ function renderSidebar() {
${state.history.slice(0, 8).map((entry) => `
${entry}
`).join("")}
+
+