South town MVP: world sim, seasons, granary, contrast test + findings
Godot 4.7 C# world simulation per SPEC.md (with 2026-07-21 amendments). 15 NPCs, 5-state machine, demand-driven work, soul-imprint triad data model, seasons with winter frost, granary, need-based gift economy, selfish-soul contrast wiring, daily/per-villager/gift CSV logging. FINDINGS.md documents the four soak experiments: the dead paradise, the buffers winning, the emergent hungry gap, and the contrast test proving the four-town thesis (and that selfishness wins until the soul-consequence layer exists). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
namespace WorldSim;
|
||||
|
||||
/// <summary>
|
||||
/// Trade evaluation and execution (SPEC §9). South MVP: generous, voluntary,
|
||||
/// no currency — a gift economy where the ratio favors the receiver.
|
||||
///
|
||||
/// Soul consequences: a generous completed exchange eases both parties'
|
||||
/// imprints (external perception — the world pressed kindly on them).
|
||||
/// Later soul types change the ratio logic only; the mechanism is shared.
|
||||
/// </summary>
|
||||
public static class TradeSystem
|
||||
{
|
||||
/// <summary>Trades since the last daily stats snapshot.</summary>
|
||||
public static int TradesToday;
|
||||
|
||||
/// <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
|
||||
/// lack remains as a fallback.
|
||||
/// </summary>
|
||||
public static bool CanTrade(Npc giver, Npc receiver, out MaterialKind material)
|
||||
{
|
||||
material = MaterialKind.Food;
|
||||
|
||||
// The ungenerous do not give. Not from an empty pack — from a full one.
|
||||
if (giver.Soul.Generosity < 0.3f) return false;
|
||||
|
||||
giver.Inventory.TryGetValue(MaterialKind.Food, out float giverFood);
|
||||
receiver.Inventory.TryGetValue(MaterialKind.Food, out float receiverFood);
|
||||
if (receiver.Nourishment < 0.6f && receiverFood < 2f && giverFood > 3f)
|
||||
return true;
|
||||
|
||||
foreach (var kv in giver.Inventory)
|
||||
{
|
||||
bool receiverLacks = !receiver.Inventory.TryGetValue(kv.Key, out float has) || has < 2f;
|
||||
if (kv.Value > 5f && receiverLacks) { material = kv.Key; return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void Execute(Npc giver, Npc receiver, MaterialKind material)
|
||||
{
|
||||
TradesToday++;
|
||||
|
||||
// Generosity decides how much of the surplus is given.
|
||||
float surplus = giver.Inventory[material] - 2f;
|
||||
float given = surplus * giver.Soul.Generosity;
|
||||
|
||||
giver.Inventory[material] -= given;
|
||||
receiver.Inventory.TryGetValue(material, out float has);
|
||||
receiver.Inventory[material] = has + given;
|
||||
|
||||
StatsLogger.LogGift(giver, receiver, material, given);
|
||||
|
||||
// The kindness lands on both atmospheres — gently.
|
||||
giver.Imprint.ExternalPerception -= 0.002f;
|
||||
receiver.Imprint.ExternalPerception -= 0.002f;
|
||||
giver.Imprint.Clamp();
|
||||
receiver.Imprint.Clamp();
|
||||
|
||||
// TODO(Week 3): soul-imprint-weighted PARTNER selection (trusted vs
|
||||
// tainted history) — the constrained-emergence reference pattern (SPEC §7).
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user