Expansion phase: settlements — the North joins the world
Runs 5-6 logged in FINDINGS.md (soul layer validated: nature debris 0.000 vs selfish 0.225 after two years; the ledger works). Towns are now real spatial structure: TownDef seeds (South at the bottom of the map, North at the top), NPCs affiliate with a home town, communal duty serves your own settlement (buildings are town-tagged, founding uses the town centroid and per-town shelter caps), and each town raises its own shelters and granary. Generational (North) soul profile added — temperament only until the knowledge system lands. Map shows town labels; rosters and CSVs carry town columns. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+72
-14
@@ -13,10 +13,25 @@ public partial class GameManager : Node2D
|
||||
public static GameManager? Instance { get; private set; }
|
||||
|
||||
[Export] public int Seed = 12345;
|
||||
[Export] public int NpcCount = 15;
|
||||
|
||||
// --- Settlements ------------------------------------------------------
|
||||
// Expansion phase: multiple towns, each a soul culture with its own
|
||||
// centroid, buildings, and granary. NPCs affiliate with a home town
|
||||
// but roam freely — the space between towns is where cultures meet.
|
||||
|
||||
[Export] public int SouthPopulation = 12; // nature souls
|
||||
[Export(PropertyHint.Range, "0,15,1")]
|
||||
public int SelfishCount = 3; // the contrast test (SPEC §11 amendment)
|
||||
public int SelfishCount = 3; // east souls living in the South
|
||||
[Export] public int NorthPopulation = 10; // generational souls
|
||||
|
||||
public record TownDef(string Name, Vector2 Center, SoulType Soul);
|
||||
|
||||
public IReadOnlyList<TownDef> Towns => _towns;
|
||||
private readonly List<TownDef> _towns = new()
|
||||
{
|
||||
new("South", new Vector2(128f, 190f), SoulType.Nature),
|
||||
new("North", new Vector2(128f, 62f), SoulType.Generational),
|
||||
};
|
||||
|
||||
[Export(PropertyHint.Range, "1,2000,1")]
|
||||
public float TicksPerRealSecond = 20f; // sim speed; ~1500 ≈ one day/sec for soaks
|
||||
@@ -68,22 +83,65 @@ public partial class GameManager : Node2D
|
||||
|
||||
private void SpawnNpcs()
|
||||
{
|
||||
// Dropped near the map center with scatter — no scripted town layout.
|
||||
// Where the community forms is the experiment (SPEC §11).
|
||||
// Dropped near their town's seed point with scatter — no scripted
|
||||
// layout. Where each community actually forms is the experiment.
|
||||
var rng = new System.Random(Seed);
|
||||
for (int i = 0; i < NpcCount; i++)
|
||||
|
||||
void Spawn(string town, Vector2 center, SoulProfile soul, int count, string prefix)
|
||||
{
|
||||
bool selfish = i >= NpcCount - SelfishCount;
|
||||
Npcs.Add(new Npc
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Name = $"Villager_{(char)('A' + i)}",
|
||||
Soul = selfish ? SoulProfile.SelfishSoul() : SoulProfile.NatureSoul(),
|
||||
PersonalityModifier = (float)(rng.NextDouble() * 0.4 - 0.2),
|
||||
Position = new Vector2(
|
||||
World.GridSize / 2f + rng.Next(-20, 21),
|
||||
World.GridSize / 2f + rng.Next(-20, 21)),
|
||||
});
|
||||
Npcs.Add(new Npc
|
||||
{
|
||||
Name = $"{prefix}_{(char)('A' + Npcs.Count % 26)}{(Npcs.Count >= 26 ? Npcs.Count.ToString() : "")}",
|
||||
HomeTown = town,
|
||||
Soul = soul,
|
||||
PersonalityModifier = (float)(rng.NextDouble() * 0.4 - 0.2),
|
||||
Position = center + new Vector2(rng.Next(-12, 13), rng.Next(-12, 13)),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var town in _towns)
|
||||
{
|
||||
if (town.Name == "South")
|
||||
{
|
||||
Spawn(town.Name, town.Center, SoulProfile.NatureSoul(), SouthPopulation, "South");
|
||||
for (int i = 0; i < SelfishCount; i++)
|
||||
Spawn(town.Name, town.Center, SoulProfile.SelfishSoul(), 1, "South");
|
||||
}
|
||||
else if (town.Name == "North")
|
||||
{
|
||||
Spawn(town.Name, town.Center, SoulProfile.GenerationalSoul(), NorthPopulation, "North");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int TownPopulation(string town)
|
||||
{
|
||||
int count = 0;
|
||||
foreach (var npc in Npcs)
|
||||
if (npc.HomeTown == town) count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
public Vector2 TownCentroid(string town)
|
||||
{
|
||||
Vector2 sum = Vector2.Zero;
|
||||
int count = 0;
|
||||
foreach (var npc in Npcs)
|
||||
{
|
||||
if (npc.HomeTown != town) continue;
|
||||
sum += npc.Position;
|
||||
count++;
|
||||
}
|
||||
if (count == 0)
|
||||
{
|
||||
foreach (var t in _towns)
|
||||
if (t.Name == town) return t.Center;
|
||||
return new Vector2(World.GridSize / 2f, World.GridSize / 2f);
|
||||
}
|
||||
return sum / count;
|
||||
}
|
||||
|
||||
public override void _Process(double delta)
|
||||
|
||||
Reference in New Issue
Block a user