Fix run-7 stone-lock collapse: construction outranks founding

Priority inversion fix: the homeless-gather-stone rule preempted all
communal work, so once everyone was homeless the town gathered stone
forever while half-built walls waited for wood that never came. Now
construction sites are first among works, homeless stone-gathering and
founding defer while any shelter is under construction, and granaries
require hunger memory + surplus (no more day-5 granary sprawl).
Run 7 logged in FINDINGS.md: in a needs-driven economy, priority
ordering is the constitution.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 14:21:41 -04:00
parent 5359ec922c
commit 41cd417601
7 changed files with 6557 additions and 3954 deletions
+22 -11
View File
@@ -210,17 +210,18 @@ public class Npc
// town's hearths. (Helping a neighbor town is a later, deliberate
// system, not an accident of the work queue.)
// 1.5. A roof of your own: kept sleeping outside? Gather stone.
// (The founding itself happens in TickBuilding once you're
// carrying enough — need drives supply drives construction.)
if (_unshelteredRests >= 3)
return MaterialKind.Stone;
// 2. Construction sites.
// 2. Construction sites — always first among works. Finishing
// the walls of a half-built shelter beats founding another
// foundation (the day-40 collapse taught us this one).
foreach (var b in gm.Buildings)
if (b.Town == HomeTown && !b.IsComplete && b.NeededMaterial is MaterialKind needed)
return needed;
// 2.5. Kept sleeping outside, and nothing in town is being
// built: gather stone to found a roof of your own.
if (_unshelteredRests >= 3 && !TownHasIncompleteShelter(gm))
return MaterialKind.Stone;
// 3. Firewood for shelters running low.
foreach (var b in gm.Buildings)
if (b.Town == HomeTown && b.WantsUpkeepWood)
@@ -252,6 +253,15 @@ public class Npc
return best;
}
/// <summary>True if this town has a shelter currently under construction.</summary>
private bool TownHasIncompleteShelter(GameManager gm)
{
foreach (var b in gm.Buildings)
if (b.Town == HomeTown && b.Kind == BuildingKind.Shelter && !b.IsComplete && !b.IsRuined)
return true;
return false;
}
/// <summary>True if this town has any granary (built or building) with room.</summary>
private bool TownHasFoodStorage(GameManager gm)
{
@@ -478,10 +488,11 @@ public class Npc
gm.Buildings.Add(site);
_unshelteredRests = 0;
}
// Carrying a surplus with nowhere to put it → the barn goes
// where the harvest is. A second granary appears when the
// first fills; storage scales with abundance.
else if (Inventory.TryGetValue(MaterialKind.Food, out float surplus) && surplus > 8f)
// Hunger remembered + a surplus with nowhere to put it → the
// barn goes where the harvest is. Founded by scarcity survived,
// not by abundance alone; another appears only when this fills.
else if (_hungerMemory &&
Inventory.TryGetValue(MaterialKind.Food, out float surplus) && surplus > 8f)
{
site = Building.NewGranary(Position + jitter);
site.Town = HomeTown;