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:
@@ -13,6 +13,42 @@ public static class TradeSystem
|
||||
/// <summary>Trades since the last daily stats snapshot.</summary>
|
||||
public static int TradesToday;
|
||||
|
||||
/// <summary>Refusals since the last daily stats snapshot.</summary>
|
||||
public static int RefusalsToday;
|
||||
|
||||
/// <summary>
|
||||
/// A hungry villager asks another for food, face to face.
|
||||
///
|
||||
/// Willingness comes from the soul (or from a warm history with this
|
||||
/// particular person). Refusing the hungry while holding food is a
|
||||
/// deliberate darkening of another — it marks the refuser's soul
|
||||
/// (others-regard debris, per DESIGN.md) and leaves a cold echo in the
|
||||
/// asker's memory. The world keeps score the only way it knows how.
|
||||
/// </summary>
|
||||
public static void RequestGift(Npc giver, Npc asker)
|
||||
{
|
||||
giver.Inventory.TryGetValue(MaterialKind.Food, out float giverFood);
|
||||
bool hasFood = giverFood > 3f;
|
||||
bool willing = giver.Soul.Generosity >= 0.3f || giver.GetWarmth(asker.Name) > 0.5f;
|
||||
|
||||
if (hasFood && willing)
|
||||
{
|
||||
Execute(giver, asker, MaterialKind.Food);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasFood && !willing)
|
||||
{
|
||||
// Refused with a full pack — the act that costs.
|
||||
RefusalsToday++;
|
||||
asker.RecordEcho(giver.Name, -0.25f);
|
||||
giver.Imprint.OthersRegard = Godot.Mathf.Clamp(giver.Imprint.OthersRegard + 0.02f, 0f, 1f);
|
||||
StatsLogger.LogRefusal(giver, asker);
|
||||
}
|
||||
// Empty-handed is not refusal: no debris, no echo. You cannot darken
|
||||
// your soul with what you do not have.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Need-based: the trigger is a person in need, not an inventory gap.
|
||||
/// Food flows to the hungry first; raw material surplus vs. genuine
|
||||
@@ -52,6 +88,10 @@ public static class TradeSystem
|
||||
|
||||
StatsLogger.LogGift(giver, receiver, material, given);
|
||||
|
||||
// Warmth lands on both sides — more on the one who was fed.
|
||||
receiver.RecordEcho(giver.Name, +0.15f);
|
||||
giver.RecordEcho(receiver.Name, +0.05f);
|
||||
|
||||
// The kindness lands on both atmospheres — gently.
|
||||
giver.Imprint.ExternalPerception -= 0.002f;
|
||||
receiver.Imprint.ExternalPerception -= 0.002f;
|
||||
|
||||
Reference in New Issue
Block a user