Files
TheriapolisV3/Theriapolis.Core/Data/SettlementLayoutDef.cs
T
Christopher Wiebe b451f83174 Initial commit: Theriapolis baseline at port/godot branch point
Captures the pre-Godot-port state of the codebase. This is the rollback
anchor for the Godot port (M0 of theriapolis-rpg-implementation-plan-godot-port.md).
All Phase 0 through Phase 6.5 work is included; Phase 7 is in flight.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 20:40:51 -07:00

91 lines
3.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Text.Json.Serialization;
namespace Theriapolis.Core.Data;
/// <summary>
/// Phase 6 M0 — describes how to lay buildings inside a settlement footprint.
///
/// Two flavours:
/// 1. **Hand-authored preset** — `kind == "preset"`. The <see cref="Buildings"/>
/// array specifies each building by template id and offset from the
/// settlement centre. Used for narrative anchors (Millhaven, Thornfield).
/// 2. **Procedural rule-based** — `kind == "procedural"`. The <see cref="Roles"/>
/// array specifies a mix of category weights ("inn" 0.1, "shop" 0.3,
/// "house" 0.6) and a target building count; <see cref="World.Settlements.SettlementStamper"/>
/// rolls templates from the matching categories until the target count is
/// met or no more building slots fit inside the plaza radius.
///
/// Bound to a settlement either by anchor name (preset) or by tier
/// (procedural fallback for any non-anchor settlement of that tier).
/// </summary>
public sealed record SettlementLayoutDef
{
[JsonPropertyName("id")]
public string Id { get; init; } = "";
/// <summary>"preset" or "procedural".</summary>
[JsonPropertyName("kind")]
public string Kind { get; init; } = "procedural";
/// <summary>For preset layouts: matches Settlement.Anchor.ToString() (e.g. "Millhaven").</summary>
[JsonPropertyName("anchor")]
public string Anchor { get; init; } = "";
/// <summary>For procedural layouts: matches Settlement.Tier (15).</summary>
[JsonPropertyName("tier")]
public int Tier { get; init; } = 0;
// ── Preset payload ─────────────────────────────────────────────────────
/// <summary>Building placements for preset layouts. Ignored when kind == "procedural".</summary>
[JsonPropertyName("buildings")]
public SettlementBuildingPlacement[] Buildings { get; init; } = Array.Empty<SettlementBuildingPlacement>();
// ── Procedural payload ─────────────────────────────────────────────────
/// <summary>Category mix for procedural layouts. Ignored when kind == "preset".</summary>
[JsonPropertyName("category_weights")]
public Dictionary<string, float> CategoryWeights { get; init; } = new();
/// <summary>Target building count for procedural layouts.</summary>
[JsonPropertyName("target_building_count")]
public int TargetBuildingCount { get; init; } = 5;
/// <summary>
/// Plaza radius in tactical tiles to search for building slots (procedural).
/// If 0, the stamper picks one based on tier.
/// </summary>
[JsonPropertyName("plaza_radius_tiles")]
public int PlazaRadiusTiles { get; init; } = 0;
}
public sealed record SettlementBuildingPlacement
{
/// <summary>BuildingTemplateDef.Id to stamp.</summary>
[JsonPropertyName("template")]
public string Template { get; init; } = "";
/// <summary>
/// Offset from settlement centre in tactical tiles. (0,0) places the
/// building's centre on the settlement centre tile.
/// </summary>
[JsonPropertyName("offset")]
public int[] Offset { get; init; } = new[] { 0, 0 };
/// <summary>
/// Optional rotation: 0 / 90 / 180 / 270. Phase 6 M0 ignores; reserved
/// so layouts don't have to be re-authored when rotation lands.
/// </summary>
[JsonPropertyName("rotation_deg")]
public int RotationDeg { get; init; } = 0;
/// <summary>
/// Override the role tag for one or more roles in this building. E.g.
/// the innkeeper template has role "innkeeper"; this preset assigns
/// it the named role "millhaven.innkeeper" so quest scripts can
/// reference the specific NPC.
/// </summary>
[JsonPropertyName("role_overrides")]
public Dictionary<string, string> RoleOverrides { get; init; } = new();
}