stop a building drifting into a recipe the player could not pick

An auto-recipe building adopted whatever recipe of its type consumed the
material offered to it, without asking the unlock state. That was the last way
a building could come to run a recipe the player could not have selected: the
selection dialog hides those and the blueprint gate discards them, but a belt
delivering the right material installed one regardless.

Automatic selection now asks isRecipeUnlocked, the same question the dialog
asks, plumbed in beside the isItemUnlocked the output pool already uses. Two
callbacks, two questions, one unlock state -- rather than a second definition of
"a recipe the player may run" written out inside the sim.

A material whose only recipes are locked now selects nothing, and an
unconfigured building has no input buffer, so that material is refused rather
than swallowed: it stays on the belt and the line backs up behind an idle
building. That is the intended failure -- a stalled belt is visible, a building
quietly eating a material the player cannot use is not.

Selection only. A recipe already set goes on producing under
REQ-LOCK-OUTPUT-POOL, which deliberately never tests a single-group recipe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
This commit is contained in:
2026-08-20 22:13:18 +02:00
parent d2b1363f6d
commit 20789cb15c
5 changed files with 80 additions and 10 deletions

View File

@@ -154,7 +154,8 @@ Any ship, module, building, or assembler recipe id that appears in no unlock gro
- REQ-BLD-ASSEMBLER: **Assembler** (3×3): The player selects a recipe from the config-defined crafting tree. Produces what that recipe produces (REQ-MAT-OUTPUT-GROUP) at the rate defined in the corresponding `recipes.toml [[recipe]]` entry with `building = "assembler"`. Only implicitly unlocked recipes are available for selection (REQ-LOCK-UI-RECIPE).
- REQ-BLD-REPROCESSING: **Reprocessing Plant** (3×3): Consumes scrap and returns a higher-tier material chosen by chance, as the value-preserving counterpart to smelting scrap down (REQ-BLD-SMELTER) and the only source of voidsteel. Its inputs, output groups and weights are ordinary recipe config (REQ-MAT-OUTPUT-GROUP) with `building = "reprocessing_plant"`; nothing about its behaviour is specific to the building. Reprocessing recipes take no part in the item traversal of REQ-LOCK-IMPLICIT (steps 23): being obtainable from a plant must never be what makes an item unlocked. They are judged for recipe unlocking like every other recipe (step 4), and what a running plant may yield is governed by REQ-LOCK-OUTPUT-POOL. Both of those read the item set; neither feeds it.
- REQ-BLD-AUTO-RECIPE: **Automatic recipe selection.** The Smelter and the Reprocessing Plant (REQ-BLD-SMELTER, REQ-BLD-REPROCESSING) are *auto-recipe buildings*. They carry a selected recipe and are configured exactly as a Miner or Assembler is — the same selection button and dialog (REQ-UI-SELECT-BUTTON), buffers sized for that one recipe alone (REQ-MAT-INPUT-BUFFER, REQ-MAT-OUTPUT-BUFFER), and the same pre-configuration on a construction site (REQ-BLD-SITE-CONFIG). They differ in one respect only:
- **Selection while none is set.** When such a building has no recipe, the first material offered at any of its input ports that some recipe of its type consumes selects that recipe; the material is then accepted as normal. This holds for every intake path — a belt, splitter or tunnel exit at an input port, and a directly coupled producer (REQ-MAT-DIRECT-COUPLE) — because a building that accepts nothing would otherwise leave a coupled producer stuck at its port forever. The choice is deterministic: input ports are examined in order, and where several recipes of the type consume the offered material the first in config order wins.
- **Selection while none is set.** When such a building has no recipe, the first material offered at any of its input ports that some **unlocked** recipe of its type consumes selects that recipe; the material is then accepted as normal. This holds for every intake path — a belt, splitter or tunnel exit at an input port, and a directly coupled producer (REQ-MAT-DIRECT-COUPLE) — because a building that accepts nothing would otherwise leave a coupled producer stuck at its port forever. The choice is deterministic: input ports are examined in order, and where several recipes of the type consume the offered material the first in config order wins.
- **Only what the player could have chosen.** Automatic selection is restricted to recipes that are currently unlocked (REQ-LOCK-IMPLICIT), the same set the selection dialog offers (REQ-LOCK-UI-RECIPE): a building must not drift into running a recipe the player could not have selected and that can yield them nothing. A material whose only recipes are locked therefore selects nothing, and since an unconfigured building has no input buffer, that material is refused rather than accepted — it stays on the belt and the line backs up behind an idle building. This is deliberate: a player who routes a material they have no use for yet gets a visibly stalled belt rather than a building quietly consuming it. The restriction applies to selection alone; a recipe already set goes on producing under REQ-LOCK-OUTPUT-POOL, which does not test a single-group recipe's output at all.
- **No further switching.** Once a recipe is set the building keeps it. It does not switch when its buffers run empty, nor when a material belonging to another of its recipes arrives — that material is simply not an accepted input, exactly as for any other building.
- **The player is always in control.** Selecting a different recipe clears the buffers (REQ-MAT-INPUT-BUFFER, REQ-MAT-OUTPUT-BUFFER); that is how a building left holding part of a cycle nothing feeds any more is freed, and how a selection the player did not want is corrected. For these buildings the dialog's clearing option is captioned `(Auto)` rather than `(None)` (REQ-UI-SELECT-OPTIONS): it unsets the recipe and hands the building back to automatic selection.
- REQ-BLD-SHIPYARD: **Shipyard** (4×2): The player selects a schematic. When all required materials — the ship's base materials (`[ship.schematic].materials`) plus the materials of all modules in the configured layout (REQ-MOD-MATERIALS) — are present in its input buffer, the shipyard consumes them and begins a production cycle lasting the ship's base `[ship.schematic].production_time_seconds` plus the sum of production times contributed by all module instances in the configured layout (REQ-MOD-PRODUCTION-TIME). One ship of that type is spawned with the configured modules when the cycle completes. The shipyard cannot start a new cycle while one is in progress. If the player confirms a layout change (REQ-MOD-UI-DIALOG) while a production cycle is in progress, the current cycle is cancelled and all consumed materials are discarded; the shipyard returns to idle with the new layout configuration. Confirming a layout identical to the one already configured is not a change and cancels nothing (REQ-MAT-INPUT-BUFFER).