Town-colored homes, split diagonally for mixed-culture households

Shelters now wear their town's culture color on the map (North cool-blue,
South green, West gold, East red), dimmed by wear; granaries stay green,
ruins dark. And bonds can now cross town lines: usually you pair within
your own people (that's who you're near), but a wanderer who warms to
someone from another town shacks up across cultures - the first quiet
thread of contact between two peoples. When two towns share a roof, the
house is drawn split diagonally, half each culture, visible across the map.

Mechanics: buildings track their top-two resident home-towns (recomputed
with occupancy, throttled to every 30 ticks since it's map-only); the
bonding rule dropped its same-town requirement. A 240-day run produced
126 bonds, 40 of them cross-town (East+North, West+South, all combos),
with populations still balanced - inter-cultural contact without
destabilizing the towns.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 21:38:57 -04:00
parent 36f6ba1f1b
commit 9e8ee1d748
4 changed files with 112 additions and 11 deletions
+41 -7
View File
@@ -83,18 +83,52 @@ public partial class Visualization : Node2D
}
// --- Map: buildings ----------------------------------------------
// Shelters wear their town's culture-color; granaries stay green;
// ruins go dark. A house shared by two towns (a mixed household) is
// split diagonally, half each culture — you can see across the map
// where someone shacked up with a neighbor from another people.
for (int i = 0; i < _gm.Buildings.Count; i++)
{
var b = _gm.Buildings[i];
Color c = b.IsRuined ? new Color(0.25f, 0.23f, 0.20f)
: b.Kind == BuildingKind.Granary
? (b.IsComplete ? new Color(0.55f, 0.70f, 0.40f)
: new Color(0.45f, 0.52f, 0.32f))
: b.IsComplete ? new Color(0.9f, 0.85f, 0.6f).Darkened((1f - b.Condition) * 0.5f)
: new Color(0.6f, 0.5f, 0.3f);
float size = CellPixels + 3f + (b.CurrentStage + b.StageProgress) * 2f + b.Modules * 1.5f;
var p = MapPos(b.Site);
DrawRect(new Rect2(p.X - size / 2f, p.Y - size / 2f, size, size), c);
var rect = new Rect2(p.X - size / 2f, p.Y - size / 2f, size, size);
if (b.IsRuined)
{
DrawRect(rect, new Color(0.25f, 0.23f, 0.20f));
}
else if (b.Kind == BuildingKind.Granary)
{
DrawRect(rect, b.IsComplete ? new Color(0.55f, 0.70f, 0.40f)
: new Color(0.45f, 0.52f, 0.32f));
}
else
{
// Base color = the house's own town culture, dimmed by wear.
float dim = b.IsComplete ? (1f - b.Condition) * 0.5f : 0.35f;
Color own = TownColor(_gm.TownSoul(b.Town)).Darkened(dim);
bool mixed = b.ResidentTownB != "" && b.ResidentTownB != b.ResidentTownA;
if (mixed)
{
// Split diagonally: town A on the upper-left triangle,
// town B on the lower-right.
Color ca = TownColor(_gm.TownSoul(b.ResidentTownA)).Darkened(dim);
Color cb = TownColor(_gm.TownSoul(b.ResidentTownB)).Darkened(dim);
var tl = new Vector2(rect.Position.X, rect.Position.Y);
var tr = new Vector2(rect.End.X, rect.Position.Y);
var br = new Vector2(rect.End.X, rect.End.Y);
var bl = new Vector2(rect.Position.X, rect.End.Y);
DrawColoredPolygon(new[] { tl, tr, bl }, ca); // upper-left ▲
DrawColoredPolygon(new[] { tr, br, bl }, cb); // lower-right ▼
}
else
{
DrawRect(rect, own);
}
}
DrawString(font, p + new Vector2(size / 2f + 2f, 4f), $"{i + 1}",
fontSize: 10, modulate: TextDim);
}