Commit Graph

438 Commits

Author SHA1 Message Date
488d706bd3 let the smelter and the plant hold one recipe like everyone else
Their buffers were unioned over every recipe of their type, so a single smelter
accepted all four ores at once, held three kinds of ingot, and ran whichever
recipe happened to be satisfiable. Four recipes coexisted in one building.

They now hold exactly one recipe, sized and cleared like any other building's,
with one addition: while none is set, the first material offered at an input
port that one of their recipes consumes selects it. That hook sits at both
intake paths -- the belt pull and the direct coupling -- because a building
that accepts nothing would otherwise leave a coupled producer stuck at its port
for good. Ports are walked in order and config order breaks a tie, so the
choice is deterministic.

Once set the recipe never changes on its own, so a material belonging to
another of its recipes is simply refused. Changing it is the player's, through
the ordinary dialog, which clears the buffers and thereby also frees a building
left holding part of a cycle nothing feeds any more; the dialog's clearing
option reads (Auto) there, since it returns the building to selecting its own.

Falling out of this: gatherCandidateRecipes collapses to getSelectedRecipe, so
tickProduction loses its candidate loop; initAutoBuffers and its union are
gone; these buildings can now be grey; and AutoProductionContent is deleted,
its two reasons for existing (the buffer-chip union and the "recipe it ran
last" fallback) having been artefacts of holding no recipe.

Also makes them configurable for blueprint purposes -- they carry a recipe now,
so a blueprint of one has something to transfer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
2026-08-12 23:10:33 +02:00
a012d1a658 give the smelter and the plant a recipe of their own
They had no recipe at all: their buffers were unioned over every recipe of
their type, so one smelter accepted all four ores at once, held three kinds of
ingot at once, and ran whichever recipe happened to have its inputs. That is
four recipes coexisting in one building.

New REQ-BLD-AUTO-RECIPE makes them ordinary selectable-recipe buildings that
size their buffers for the one recipe they hold, with a single addition: while
no recipe is set, the first material offered at an input port that any of their
recipes consumes selects it. That covers every intake path, direct coupling
included -- a building that accepts nothing would otherwise leave a coupled
producer stuck at its port forever. Ports in order, config order as tie-break,
so the choice is deterministic.

Once set the recipe never changes on its own, which is what settles the case of
recipes sharing some inputs but not others: there is no second guess to make.
The player changes it through the ordinary selection dialog, which clears the
buffers and so also frees a building holding part of a cycle nothing feeds any
more -- no separate clear action is needed. The dialog's clearing option reads
(Auto) rather than (None) there, since it returns the building to automatic
selection rather than leaving it idle.

Consequently these buildings can now be grey, have a recipe control in the
selection card, and drop the special cases they needed for having no recipe to
name: the buffer-chip union and the recipe summary's "recipe it ran last".

Requirements only; the implementation follows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
2026-08-12 22:44:11 +02:00
1088b88692 name the output section for the several buffers it now holds
A building has one output buffer per item it can produce, so the singular
caption no longer matches what the section lists -- and the input side, which
has always had one buffer per material, already read "Input buffers".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
2026-08-12 22:10:00 +02:00
993b73a4c3 size the output buffer per item instead of per building
Implements the requirements from 8401b20. OutputBuffer's type-blind `capacity`
becomes a `caps` map keyed by item, mirroring InputBuffer. The items stay in
one production-ordered vector, because that order is what the output port hands
out (REQ-MAT-OUTPUT-EMERGE); only the capacity is now per type, so one item's
backlog no longer occupies another's room.

The cycle gate moves ahead of the roll in tickProduction: recipeOutputsFit()
requires every output a cycle could produce to fit, which for a deterministic
recipe is just its own outputs and for the Reprocessing Plant is every possible
roll. That is what denies the reroll the old one-item cap was there for -- a
full buffer for one item stops the plant entirely rather than letting it keep
producing the others -- while letting it hold two cycles' worth per outcome and
produce amounts above one.

getCycleOutputItemCount(), which judged the plant by the smallest amount any
roll could yield, is gone: it only existed because the classifier could not know
the roll, and the all-outcomes rule needs no such approximation. Its unlock
caveat goes with it, since a locked item is never produced and so never fills.

The Salvage Bay's config-defined capacity becomes its single scrap cap, and the
shipyard simply has no caps at all. The checksum hashes the map the way the
input caps are hashed, so determinism is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
2026-08-12 16:46:54 +02:00
8401b20d35 give each output item its own buffer
The Reprocessing Plant held at most one cycle's output, so a single item
anywhere in the building -- buffer or still emerging -- stopped the next cycle.
That cap existed only to deny a reroll: with room for one item, stalling the
output belt could not make the plant discard a roll and try again.

Replace it with the general rule. Every item a recipe can produce gets its own
buffer of twice its per-cycle amount, mirroring the input side, and a cycle
starts only when every output it could produce fits. For a deterministic recipe
that is just its own outputs, so nothing changes there. For the plant it means
all possible rolls must fit, which denies the reroll as before -- a full buffer
for one item stops the plant entirely rather than letting it go on producing
only the others -- while allowing an output amount above one.

Also pins what "the next buffered item" means at the output port now that one
queue no longer implies it: items leave in production order whatever their
type. Status light and output chip wording follow, since a buffer short of a
full cycle's worth blocks exactly as a full one does.

Requirements only; the implementation follows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
2026-08-12 16:04:09 +02:00
1d54ecf578 start the next production cycle in the tick the last one completed
tickProduction and tickShipyardProduction cleared the finished cycle and then
refused to start another in the same tick, so every cycle really took its
duration plus one tick. The cost scales inversely with duration: a 1s recipe
ran at 31 ticks instead of 30 and lost 3.2% of its throughput, a 12s recipe
0.3%, which skewed the relative rates the recipe tree is tuned around.

Fall through from completion into the start attempt instead. The start code is
straight-line, so at most one cycle still begins per building per tick, even
for a duration that rounds to zero ticks, and the outputs just deposited count
against the space check, so a cycle whose output no longer fits waits exactly
as it did before.

The balancing model already computed rates as amount / duration_seconds
(tools/threat_report.py), so this brings the simulation up to the documented
numbers rather than moving them. The combat arena never ticks production, so
its tuning is untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
2026-08-12 12:49:56 +02:00
74233f5bc5 show green while a building is only between cycles
tickProduction never starts a cycle in the tick one completed, so a building
running back to back is idle for exactly one tick per cycle. The status light
classified that tick as "output full" -- hasInputsToStart looks at the input
buffers alone -- so the pill blinked green/yellow once per cycle, roughly once
a second on a one-second recipe.

REQ-UI-STATUS-LIGHT already says a building that is idle yet blocked by
neither condition shows green. Add canStartCycle(), which requires a candidate
recipe's inputs *and* room for its output, and classify on it; yellow now
needs an output buffer that genuinely cannot take the next cycle. The
Reprocessing Plant rolls its output in the simulation, so the classifier
judges it by the smallest amount any roll could yield.

tickProduction's space check goes through the same outputBufferHasRoom(), so
the simulation and the light cannot drift apart.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
2026-08-12 12:38:21 +02:00
ab4aef2ad5 ask the icon cache for the inline block icon
The three block-icon call sites each spelled out the same expression that
ItemIconCache::getInlineIcon() now is: the bare icon at the line's text
height, null when the file is missing. They call the helper instead, and
HeaderBar::blockIcon() -- which was that expression and nothing else --
is gone along with its stale "loaded once on first use" comment.

Each site still passes its own widget font, so nothing about the sizing
changes; the rule now lives in one place rather than four.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
2026-08-12 10:34:20 +02:00
344d18a5d1 draw the scrap of a debris card as an icon, not a word
The debris card's row now reads "Remaining" with the amount and the bare
scrap icon after it, and the count summary's indented sub-row states its
total the same way; both fall back to naming the item in words when no
scrap icon file exists.

StatRow gained the value-plus-icon form: a label draws either text or a
pixmap, so the two are composed into one via renderCaptionWithIcon, with
the color passed in because a pixmap does not follow the palette. That
also closes a gap in the building multi-selection, whose "Total cost" was
specified to carry the building_block icon and showed the bare number.

ItemIconCache::getInlineIcon() packages the sizing rule of the bare inline
icon. It sits on the cache rather than in IconCaption so StatRow keeps
pulling in nothing but the caption helper: StatRow.cpp is compiled into
DotaFactory_balancing, which links neither the ui library nor QtSvg, and
that target now compiles IconCaption.cpp along with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
2026-08-12 10:14:04 +02:00
3a4b69b520 state the debris scrap value with the item icon, not the word
The debris panel's stat row spelled out "Scrap remaining". It now reads
"Remaining" with the amount followed by the bare scrap icon -- the same
inline form the header bar uses for building blocks -- and falls back to
the old caption when no scrap icon file exists. The count summary's
indented sub-row states its sum the same way.

REQ-UI-ITEM-ICON named the bare inline icon as a building_block special
case; it now states the general rule (an icon standing in for the item's
name beside a number is drawn without its square) and keeps the boundary
explicit: a value shown as an item still takes the square.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
2026-08-12 09:52:21 +02:00
8d0dd6f454 name recipes after their process, not their product
Recipe display names come from the id, so a recipe that shared its id with
its output item showed the item's name back to the player. Every recipe id
now names the process that runs it: iron_mining, quartz_reduction,
steel_rolling, chip_etching, the *_framing hulls, the *_kit module prefabs,
and the drop-only shortcuts as direct_rolling/-etching/-hardening.

The three shortcut unlock groups are renamed with their recipes, since a
group's name is derived from its id the same way.

Blueprints and replays store recipe ids, so files recorded before this
rename lose their miner and assembler recipe selections.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
2026-08-12 09:16:19 +02:00
bd8fe5157e add border around recipes where several of them stack 2026-08-12 08:30:10 +02:00
a3fddf63cc give a recipe line its own row for its identity 2026-08-11 22:07:15 +02:00
1ddd830476 fix requirements: let the layout preview state that it shows color alone 2026-08-11 22:07:02 +02:00
f255224ccd show recipes visually instead of describing them in text 2026-08-11 21:47:35 +02:00
3274df91d4 open selection panel modals on the panel 2026-08-11 21:21:12 +02:00
d1da4b2937 color item icon backgrounds in the UI from visuals.toml 2026-08-11 21:18:52 +02:00
37378e3c1b allow to move the selection panel via mouse drag 2026-08-09 22:09:41 +02:00
37a7a7499a update item box color to yield better contrast 2026-08-09 21:34:31 +02:00
5794a51c9a draw boxes around item icons 2026-08-09 21:20:47 +02:00
09858f4b62 keep an auto-recipe building's summary between its cycles 2026-08-09 20:41:48 +02:00
ca49b9dbec let the world renderer hold the simulation by const reference 2026-08-09 20:37:15 +02:00
79650ae211 make EntityAdmin::hasAll const 2026-08-09 20:37:09 +02:00
c0b009c548 place the selection panel beside what it describes 2026-08-09 20:36:58 +02:00
7ae5f8c4dc fix selection panel contents 2026-08-07 22:01:10 +02:00
9f574fa05e fix issue where the selection panel sometimes collapses to very small size 2026-08-07 21:17:53 +02:00
e5d689c8d8 document the player-input design in architecture.md 2026-08-07 20:43:12 +02:00
0b8f5eccd6 scroll the controls panel's rows instead of clipping them 2026-08-07 20:42:56 +02:00
40415e663b put the controls panel in the corner and let it step around the build bar 2026-08-07 20:42:41 +02:00
7a098edf72 mark the exit row of the controls panel red on its chips instead of its label 2026-08-07 19:52:51 +02:00
365641feb7 size the controls panel to the rows it is actually showing 2026-08-07 19:38:10 +02:00
4b5e288632 record that additive selection is offered only once something is selected 2026-08-07 19:10:26 +02:00
cab7244b00 divide the always-available rows in the General context too 2026-08-07 19:10:04 +02:00
980fad272f show the available controls in a panel over the world 2026-08-07 18:48:01 +02:00
68a43a7d98 resolve mouse gestures through the action table too 2026-08-07 18:47:43 +02:00
1f754de431 resolve keyboard shortcuts through one action table instead of a switch 2026-08-07 18:47:29 +02:00
f61f0bf761 add requirements for a context-sensitive controls panel floating over the game world 2026-08-07 18:47:15 +02:00
075e44d295 give the selection cards their own parts instead of label blobs 2026-08-07 18:43:23 +02:00
2289277e12 split the selection panel into one card per kind of selection 2026-08-07 18:38:55 +02:00
cc0ef856e3 make asteroid smaller 2026-08-06 22:14:02 +02:00
603f8063e9 float the selection panel over the game world instead of a side column 2026-08-06 22:06:42 +02:00
3b37b0ecf8 target single-building transfers by hovering, not by footprint coincidence 2026-08-06 20:31:51 +02:00
98deab932a let any blueprint transfer configuration, not just single-building ones (if the orientation matches) 2026-08-06 20:29:20 +02:00
08d8b0dd90 re-cover copy-settings through single-building blueprints 2026-08-06 19:44:55 +02:00
9a3b6c10d6 fix bug where selecting the same layout for a shipyard discarded the current progress and buffers 2026-08-06 19:18:45 +02:00
cd31af2611 remove the Shift copy-building-settings gesture 2026-08-06 19:09:11 +02:00
fd6a7c5815 rekey the temporary blueprint to C, add V to re-place it 2026-08-06 19:07:13 +02:00
18cfe238f6 move blueprints out of the sidebar into Ctrl+C / Ctrl+V dialogs 2026-08-06 19:03:59 +02:00
2cbcf1554f add the ASCII-only source rule and the visual-verification note to CLAUDE.md 2026-08-06 08:28:57 +02:00
c1af58d80c float the build buttons as a horizontal bar over the game world and show key bindings inside build buttons 2026-08-06 08:28:40 +02:00