128 lines
11 KiB
Markdown
128 lines
11 KiB
Markdown
# 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_undiscovered` is the existing `location-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/sim` stays pure, all numbers live in `packages/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.md` for every schema or API change and `progress.md` after 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_undiscovered` error. 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_boards` to 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 update `game-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.
|