11 KiB
Change Request CR-002 — Open Markets, Bays as HQs
Project: Deadhead: Space Freight Tycoon
Applies to: a build with Phases 1–10 and CR-001 (Faster Start) complete
Do this: as Phase 10B, after Phase 10A and before Phase 11
Related docs: implementation-plan.md, change-request-faster-start.md, game-design-document.md, DECISIONS.md
Numbering note (added when implemented): the plan's §0.5 already used 27 (pilot location storage), 28 (Git hosting) and 29–34 (CR-001). The new decisions below numbered 0.5.27 and 0.5.28 are recorded as 0.5.35 Ship delivery and 0.5.36 Undiscovered locations. The error code
location_undiscoveredis the existinglocation-undiscovered.
1. Why
Contracts are currently only offered at locations where the player has a bay, and repositioning is only allowed to and from bay locations. A ship that delivers to a location without a bay (for example the Moon) is stranded: there is no contract board there, and it cannot reposition home.
The fix follows the American/Euro Truck Simulator model:
- Every discovered location has a contract board (the freight market). Any idle ship can pick up work wherever it is, which makes backhaul work.
- Bays are HQs (like ATS garages). You need a bay to hire pilots there, to take delivery of newly bought ships there, and to unassign pilots there. Bays no longer control where contracts are available.
- Discovery still gates expansion. An undiscovered location has no board until the player delivers there.
2. Rules for this change
- All rules in
implementation-plan.md§0.1 still apply: steps in order, one commit per step, each step's test must pass,packages/simstays pure, all numbers live inpackages/content. - Do not write data migrations for old contract boards. Resetting the dev and test databases is fine. Schema migrations are still required.
- Update existing tests whose expectations change. Do not delete a test unless §5 says the step is replaced.
- Update
architecture.mdfor every schema or API change andprogress.mdafter every step. - Stop for the user's review at the end of Phase 10B.
3. Decision changes
Record these in DECISIONS.md and in implementation-plan.md §0.4 and §0.5.
Glossary changes (§0.4)
- Bay → A docking bay the player leases at a discovered location. It is an HQ: pilots are hired there, newly bought ships are delivered there, and pilots can be unassigned there. A bay does not control where contracts are offered.
- Contract board (new) → The freight market at a discovered location. Every discovered location has one per player per board period, whether or not the player has a bay there.
- Deadhead (new) → A reposition: a ship flying empty to another location. Fuel only, no payout, no XP.
Replaced
- 0.5.5 (Contract boards are stored) → A board exists for every discovered location, per player, per period. It is generated on the first request in a period and stored; later requests in that period return the stored board. Every contract expires at the end of its board period. (Amended by CR-019:) a stored location board also records the qualifying fleet it was generated for, and reads hide jobs the current qualifying fleet can't complete (Step 19.3).
- Step 3.14 rule (reposition only to a bay) → An idle ship can deadhead from any location to any discovered location other than its current one, subject to the normal range and landing checks.
New
- 0.5.27 Ship delivery. Buying a ship requires choosing one of the player's bays. The new ship appears there, idle and uncrewed.
- 0.5.28 Undiscovered locations. Requesting the board of an undiscovered location fails with a
location_undiscoverederror. Deadheading to an undiscovered location is not allowed; only a contract delivery discovers a location.
Unchanged (confirm, don't modify)
- 0.5.2 Pilot locations. Hiring happens at a player bay; unassigning is allowed only at a location with a player bay.
- CR-001 deal. The deal still includes the Earth bay.
4. Steps — Phase 10B
Step 10B.1 — Sim: boards at any location
- Change the contract board generator's input from "the bay's location" to "the board's location". No other generation rules change.
- Rename any sim types or functions that say "bay board" to "location board".
- Test: The Step 3.9 tests still pass with a location input. Generating a board for the Moon with no bay data supplied anywhere works and is deterministic.
Step 10B.2 — Sim: deadhead validation
- Reposition validation allows any origin. The destination must be discovered, must differ from the origin, and must pass the range and landing checks. The bay requirement is removed.
- Update the Step 3.14 tests.
- Test: A Courier idle at the Moon with no Moon bay can deadhead to Earth. Deadheading to an undiscovered location fails with
location_undiscovered. Deadheading to the ship's own location fails. Deadheading out of range fails with the out-of-range reason. A deadhead record still has zero payout and zero XP.
Step 10B.3 — Database: boards keyed by location
- Change
contract_boardsto be keyed by player, location, and board period (the tutorial board keeps its own key). - Update
architecture.md. - Test: Migrations run on a fresh database and are a no-op the second time. Two boards for the same player and period at different locations can coexist; a second board for the same player, location, and period is rejected by a unique constraint.
Step 10B.4 — Server: board endpoint for any discovered location
- Replace "get contract board for a bay" with "get contract board for a location" in the route catalog and server. Any discovered location works; an undiscovered location returns
location_undiscovered. - Update the Step 6.9 tests.
- Test: The Moon's board is returned for a player with no Moon bay. Two requests in the same period return the same board. Requesting Mars's board before discovery fails with
location_undiscovered; after a delivery discovers Mars, it succeeds.
Step 10B.5 — Server: no more stranded ships
- Contract dispatch works from any discovered location where the ship is idle (it already validates that the ship is at the contract's origin; confirm no bay check remains).
- Deadhead dispatch uses the Step 10B.2 rules.
- Update the Step 6.10 and 6.11 tests.
- Test (the original bug): A ship delivers Earth→Moon with no Moon bay. After arrival, the Moon's board is available, a Moon→Earth contract can be dispatched with that ship, and it resolves normally. Separately, the same ship can instead deadhead Moon→Earth.
Step 10B.6 — Server: ship delivery to a bay
- Buying a ship takes a bay id. The ship appears idle and uncrewed at that bay's location. Buying without a bay, or with a bay the player doesn't own, fails.
- Update the Step 6.5 tests.
- Test: With bays at Earth and the Moon, buying a Freighter for the Moon bay places it at the Moon. Buying with no bay id fails with a validation error. Buying with another player's bay id fails and changes nothing.
Step 10B.7 — Client: Contracts screen by location
- The Contracts screen's selector lists all discovered locations instead of bays. Each entry shows a badge with the number of idle ships there.
- Default selection: the location of the most recently arrived idle ship; otherwise Earth.
- Fleet screen: each idle ship gets a "Find work here" action that opens its location's board.
- Update the Step 9.4 tests.
- Test: Component test: the selector lists every discovered location and no undiscovered ones; idle-ship badges match state; the default is the most recently arrived idle ship's location; "Find work here" opens the right board.
- Amended (decision 0.5.164): "Find work here" is disabled when the ship can't be dispatched now: its pilot is resting (CR-004; rest beside service, CR-023/CR-027, included), it's in the shop for an upgrade, repair or service (CR-009/CR-026/CR-027), or it has no pilot. The button says why with the countdown that ends last ("Resting · 04:12", "In the shop · 12:30", "No pilot assigned") and re-enables on its own when it ends. Every ship, Independent pilots' included; the Contracts tab stays browsable.
Step 10B.8 — Client: deadhead action
- Rename the Fleet screen's "Reposition" action to "Deadhead (fly empty)". It is available for every idle ship. The destination picker lists discovered locations; ones out of range or not landable are shown disabled with the reason. Show fuel cost and trip time for each.
- Update the Step 9.6 tests.
- Test: Component test: an idle ship at the Moon with no Moon bay shows the action; the picker excludes undiscovered locations and the ship's current location; an out-of-range destination is disabled with its reason; fuel and time match the sim.
Step 10B.9 — Client: bays as HQs
- Market screen: "Buy" opens a bay picker ("Deliver to which HQ?"). With only one bay, preselect it.
- Locations screen and map panels: every discovered location has a "View contracts" link. The "Lease bay" action explains what a bay does: "Open an HQ here: hire pilots and take delivery of new ships at this location."
- Update the Step 9.8, 9.9, and 10.3 tests.
- Test: Component test: Buy shows the bay picker and sends the chosen bay id; with one bay it is preselected. Every discovered location shows "View contracts", with or without a bay. The lease action shows the HQ explanation.
Step 10B.10 — Plan amendments and regression
- Apply the amendments in §5 to
implementation-plan.md, and updategame-design-document.md§4 and §10 to match §1 of this document. - Run the full suite.
- Test: CI is green. Manual check: on a fresh account after the CR-001 deal, deliver to the Moon, pick up a Moon→Earth contract with the same ship, and deliver it back to Earth without leasing a Moon bay.
5. Amendments to implementation-plan.md
| Step | Change |
|---|---|
| 0.4, 0.5 | Apply §3 of this document. |
| 3.9 | Input is a location, not a bay (10B.1). |
| 3.14 | Deadhead rules replace reposition-to-bay (10B.2). |
| 5.3 | contract_boards keyed by player, location, and period (10B.3). |
| 6.5 | Ship purchase takes a bay id (10B.6). |
| 6.9 | Boards for any discovered location (10B.4). |
| 6.10, 6.11 | No bay checks on dispatch; deadhead rules (10B.5). |
| 9.4 | Selector lists discovered locations (10B.7). |
| 9.6 | "Deadhead (fly empty)" for every idle ship (10B.8). |
| 9.8, 9.9, 10.3 | Bay picker on purchase; "View contracts" everywhere; HQ explanation (10B.9). |
| 12.1 | The simulated player picks up contracts at whatever location its ships are at, and only deadheads when no eligible contract exists there. Add a check: across the whole run, no ship is ever idle with no eligible contract and no reachable deadhead destination. |
| 12.5 | After Mars is discovered, also confirm Mars's contract board is available without a Mars bay. |
6. Out of scope
Garage-style bay capacity or slot limits, bay upgrades, recurring bay rent, pilots that pick their own jobs from their home bay (ATS-style AI drivers), and anything else in implementation-plan.md §0.3.