Let any worker stock a completed building (draft: keep the schooling gate for sites only) - #255
Let any worker stock a completed building (draft: keep the schooling gate for sites only)#255Giszmo wants to merge 2 commits into
Conversation
MeasurementEight Nicowars on Playground, resumed from the tick-25000 saves, run to 40000, ASLR off (
Read: starvation deaths drop on five of six seeds, deliveries are up on the two seeds where the AI had upgraded inns it could not staff (11, 13) and flat elsewhere; seed 7 goes the other way and is the noisy one. Consistent with the mechanism: Nicowar upgrades inns freely and this lets its unschooled workers feed them. Not a large effect on this bed, and this bed is AI-only; the human-play question above is the one that decides the PR.
|
A worker has two schooling levels that mean the same thing. Only the school raises either, it raises both in one visit (upgradeInParallel), and nothing else in the game tells them apart: the harvest level gated which building tier a worker may work for and its chop speed, the build level gated which upgrades the menu offers (Team::maxBuildLevel) and its fill speed. So the hiring gate and the upgrade button read different numbers for the same question, and the map editor offered two boxes for one value. Set apart in the editor, a unit could be allowed to upgrade a building it was then refused by. Make it one value: - Unit::workerLevel() reads it; Unit::setWorkerLevel() sets both halves and their performance together. The hiring gate, Team::maxBuildLevel and the fetch ranking read through it. - A unit loaded with the two apart keeps the higher one, so maps edited before this keep working and cannot desync on it. - A non-parallel upgrade of build or harvest raises both. - The editor keeps the build box and drops the harvest box; the unit panel drops the Harvest row, which always showed the Build value. The save format and race tables are untouched; both abilities are still stored and still drive their own speeds. A real-engine harness (test/LevelGateHarness.cpp, target level-gate-test, run in CI) checks the gate against completed buildings and sites and that a level-2 site hires build 1 with harvest 0 and refuses the reverse. Simulation behaviour can change for maps with the two levels apart, so VERSION_MINOR goes to 96 and replays older than that are refused. (cherry picked from commit e5b1cf6) Fable 5.1 helped authoring this commit.
`Building::canUnitWorkHere` gated every fetch job for a worker on the building's level: a worker could only carry to a building whose level was at most its harvest level. That gate dates from the 2007 unit allocation rewrite and has one plain reading -- raising or upgrading a level-N building takes a worker schooled to level N -- but it also applied to completed buildings that only want stock: a level-2 or level-3 inn wanting wheat and fruit, a level-2 or level-3 tower wanting stone. An unschooled worker standing next to a hungry level-3 inn with wheat on its back was refused, and the building panel counted it under "units too low level". Keep the gate for construction and upgrade sites, drop it for completed buildings. Any worker can carry. The real-engine check in test/LevelGateHarness.cpp runs one hiring pass per case: a level-0 worker is hired by completed level-2/3 inns and a level-3 tower, is refused by a level-2 inn site, and level-1/2 workers are hired by level-2/3 sites. Built with the level-gate-test target and run in CI like the other hiring harnesses. Simulation behaviour changes, so VERSION_MINOR goes to 97 and replays older than that are refused. No save-format change. (cherry picked from commit 4c00685) Fable 5.1 helped authoring this commit.
4c00685 to
6d80c86
Compare
Deliveries over time, master vs this branchSame bed and protocol as the first comment (eight Nicowars, tick-25000 saves, run to 40000, ASLR off, Deliveries per 2048-tick window, summed over the six seeds and all teams; "upgraded" = completed level-2/3 inns + towers, summed over seeds, at window end.
Per seed, deliveries from the first upgraded building (tick 25088 on every seed) to the end, master / this: 7: 3256 / 3124, 11: 2810 / 3038, 12: 1768 / 1780, 13: 2640 / 2890, 14: 2919 / 2903, 15: 2951 / 2903. Four up, two down; the two down are seed 7 (the heap-sensitive one, see #253) and seed 15 (−1.6%). Read: the branch runs ahead for the first six windows, by 2–12%, while the colonies are upgrading and unschooled workers can now feed the new inns, and falls behind in the last two windows, when it has more upgraded buildings and more units alive (population +2.3% at the end, starvation −16%) and the AI economies saturate. Fill 85 gives the same shape (+2.5 / +7.0 / +11.2 / +2.0 / +3.2 / −6.9 / −5.7%). Net over the run +2.2% deliveries, as in the first comment. Same conclusion: a modest, front-loaded gain on the AI bed; the decision is the human-play one. |
|
Closed on Leo's call: the effect is real (up to +12% deliveries per window on the AI bed), which means the schooling gate is a real balance lever and stays. The player-facing problem is that the game does not show which units fail the gate; that gets its own PR: red shapes next to the failure counts in the building panel, and the same shapes over the exact units in the map view. |
Draft for discussion. Stacked on #256 (first commit is that one; the second is this change). One-line behaviour change plus harness cases; the question is whether the game should work this way.
What the code does today
Building::canUnitWorkHere(src/building/Misc.cpp) refuses a worker for any fetch job at a non-flag building whosetype->levelis above the worker'slevel[HARVEST]. That covers construction and upgrade sites, which is the reading everyone has of the rule ("you need schooled workers to build level 2"), but it equally covers completed buildings that only want stock:A level-0 worker four tiles from a completed level-2 inn, carrying wheat, is refused with
UnitTooLowLevel(real-engine run on master, see the harness in this PR). Only the school raises the harvest level, and it raises harvest and build together, so in a normal game the gate is invisible: you cannot upgrade an inn without schooled workers, and once you have them they also feed it. It bites when the schooled units are busy, dead, or few: every unschooled worker in the colony is then barred from feeding the upgraded inns and stocking the upgraded towers, and the only sign is the "N units too low level" line in the building panel.The upgrade button is gated separately on
Team::maxBuildLevel(); #256 underneath this makes both read the same worker level.The change
Keep the gate for sites (
type->isBuildingSite), drop it for completed buildings. Any worker can carry.VERSION_MINOR96 → 97 and the replay floor with it; no save-format change.Gameplay discussion (please weigh in)
For lifting it
[%0 units too low level]is the only string that mentions it, one of eight failure reasons in the building panel, and the tutorial and help texts do not cover it (grep overdata/texts.en.txtanddocs/). A player with many level-2 towers and few schooled workers gets towers that never fill and has to work out why.Against lifting it
timeToFeedUnit24 → 15 → 9), so this makes the upgrade cheaper to sustain.My read: lift it. The rule punishes a state the game never explains, and the strategic content (school before you upgrade) survives in the site gate. But this is a feel decision for a maintainer, per CLAUDE.md.
Measurement
Eight Nicowars on Playground, resumed from a tick-25000 save, run to 40000, ASLR off,
MALLOC_PERTURB_swept over 0/85/170 (the protocol from #253; this branch does not carry that fix, so the spread across fills is reported rather than hidden). End-of-run totals are in the first comment. Leo's point stands that the effect can only start once the first inns and towers are upgraded, so a per-512-tick series of deliveries against the count of upgraded buildings is being measured and will follow in a second comment.Verification
level-gate-testharness (from Read one worker level where hiring read harvest and the menu read build #256, cases updated here): a level-0 worker is hired by completed level-2/3 inns and a level-3 tower, refused by a level-2 site; level-1/2 workers build level-2/3 sites;build=1, harvest=0builds a level-2 site. On master the three completed-building cases fail withUnitTooLowLevel.TestsRunner(187) green.🤖 Generated with Claude Code