Soul layer: imprints, warmth echoes, and consequences

Ports the Unity POC soul systems into the sim:
- Warmth echoes: villagers remember who fed them (+0.15) and who turned
  them away (-0.25). Ask-for-food targeting runs on memory, not
  omniscience; the remembered-cold are not asked. Echoes fade daily.
- Refusing the hungry while holding food marks the refuser (others-regard
  debris) and is logged; empty-handed is not refusal.
- Harvesting below the 50% commons line marks the taker per unit taken.
- Soul-to-soul atmospheric pressure (SoulFieldSystem port): encased souls
  darken nearby atmospheres, clear souls lighten them.
- Debris costs biologically: nourishment drains faster and meals restore
  less as the soul encases.
- Instrumentation: avg_debris + refusals in daily stats; per-villager
  nourish/health/debris; refusals in the contact log; map dots dim with
  encasement.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 13:07:33 -04:00
parent 0ba5341f0e
commit ed78d560ff
6 changed files with 156 additions and 22 deletions
+13 -2
View File
@@ -74,17 +74,28 @@ public class World
/// <summary>
/// Harvest respecting the harvester's sustainability weight:
/// a South soul stops at ~50% of the node (SPEC §10) so nodes stay healthy.
/// Taking from below the commons line marks the taker's soul — it is
/// taking from everyone, whether anyone sees it or not.
/// Returns the amount actually taken.
/// </summary>
public float Harvest(ResourceNode node, float requested, SoulProfile soul)
public float Harvest(ResourceNode node, float requested, Npc npc)
{
if (node.Kind == MaterialKind.Water) return requested; // unlimited at source
float floorFraction = soul.Sustainability * 0.5f; // how much of the node they leave standing
float floorFraction = npc.Soul.Sustainability * 0.5f; // how much of the node they leave standing
float takeable = Math.Max(0f, node.Amount - node.MaxAmount * floorFraction);
float taken = Math.Min(requested, takeable);
node.Amount -= taken;
HarvestedToday += taken;
float commons = node.MaxAmount * 0.5f;
if (node.Amount < commons)
{
float takenBelow = Math.Min(taken, commons - node.Amount);
npc.Imprint.OthersRegard =
Math.Clamp(npc.Imprint.OthersRegard + takenBelow * 0.004f, 0f, 1f);
}
return taken;
}