diff --git a/DECISIONS.md b/DECISIONS.md index f952f54..b95d419 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -874,3 +874,11 @@ Implementation decisions not spelled out in `memory-bank/implementation-plan.md` - **`contractBoardPeriodRealMinutes` 60 → 10 and `restGameHours` 60 → 10** (user request, after Phase 10D). At 60× compression a rest is now 10 real minutes, exactly one board period, so decision 0.5.46 still holds and its content test (rest in real time ≥ board period) is unchanged and passing. - **Effects:** boards refresh every 10 real minutes and every contract expires at the end of its period, so offers turn over six times as fast. A rested pilot is back in 10 minutes instead of an hour. This also resolves the earlier note that the CR-004 example expected a short rest. - **Two tests assumed a 60-minute period** and now derive their timing from config instead: the server's `testContract` helper (expiry = end of the board period) and the board-refresh countdown test. No game code changed. + +## CR-006 — Boards That Fit Your Fleet (Phase 10F) + +- **Requested by the user** after CR-005: highlight weight a ship can't carry, and offer more jobs that fit the player's ships and pilot skills than the one guaranteed job per band. Stored in `memory-bank/change-requests/`, inserted as Phase 10F before Phase 11; decisions are plan §0.5.52–0.5.53. + +## Step 10F.1 + +- **"Your ship" means the ships at the board's location**, because those are the ones that can take the job now; with none there, the whole fleet (one of them could deadhead in). Ships in flight have no location, so they only count in the fallback. diff --git a/apps/web/src/screens/LocationBoards.tsx b/apps/web/src/screens/LocationBoards.tsx index 02bbcce..a5c5d1d 100644 --- a/apps/web/src/screens/LocationBoards.tsx +++ b/apps/web/src/screens/LocationBoards.tsx @@ -34,6 +34,18 @@ export function requirementsText(contract: Contract): string | null { return parts.length > 0 ? parts.join(", ") : null; } +/** + * The most a player's ship can carry for a board at this location: the largest + * ship here, or in the whole fleet when none are here; null with no ships + * (decision 0.5.53). + */ +export function carryLimit(state: PlayerState, locationId: string): number | null { + const here = state.ships.filter((s) => s.locationId === locationId); + const ships = here.length > 0 ? here : state.ships; + if (ships.length === 0) return null; + return Math.max(...ships.map((s) => content.shipModel(s.modelId)?.cargoCapacityTonnes ?? 0)); +} + /** * The location the Contracts screen opens on: where the most recently arrived * idle ship is, otherwise Earth (CR-002). @@ -107,7 +119,9 @@ function LocationBoard({ onSelect?: (contract: Contract) => void; }) { const api = useApi(); + const state = useLoadedPlayer(); const now = useClock((s) => s.now); + const limit = carryLimit(state, locationId); const board = useQuery({ queryKey: locationBoardKey(locationId), queryFn: () => api.call("getContractBoard", { locationId }), @@ -161,6 +175,7 @@ function LocationBoard({