using System.Text.Json.Serialization; namespace Theriapolis.Core.Data; /// /// Phase 6 M0 — describes how to lay buildings inside a settlement footprint. /// /// Two flavours: /// 1. **Hand-authored preset** — `kind == "preset"`. The /// 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 /// array specifies a mix of category weights ("inn" 0.1, "shop" 0.3, /// "house" 0.6) and a target building count; /// 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). /// public sealed record SettlementLayoutDef { [JsonPropertyName("id")] public string Id { get; init; } = ""; /// "preset" or "procedural". [JsonPropertyName("kind")] public string Kind { get; init; } = "procedural"; /// For preset layouts: matches Settlement.Anchor.ToString() (e.g. "Millhaven"). [JsonPropertyName("anchor")] public string Anchor { get; init; } = ""; /// For procedural layouts: matches Settlement.Tier (1–5). [JsonPropertyName("tier")] public int Tier { get; init; } = 0; // ── Preset payload ───────────────────────────────────────────────────── /// Building placements for preset layouts. Ignored when kind == "procedural". [JsonPropertyName("buildings")] public SettlementBuildingPlacement[] Buildings { get; init; } = Array.Empty(); // ── Procedural payload ───────────────────────────────────────────────── /// Category mix for procedural layouts. Ignored when kind == "preset". [JsonPropertyName("category_weights")] public Dictionary CategoryWeights { get; init; } = new(); /// Target building count for procedural layouts. [JsonPropertyName("target_building_count")] public int TargetBuildingCount { get; init; } = 5; /// /// Plaza radius in tactical tiles to search for building slots (procedural). /// If 0, the stamper picks one based on tier. /// [JsonPropertyName("plaza_radius_tiles")] public int PlazaRadiusTiles { get; init; } = 0; } public sealed record SettlementBuildingPlacement { /// BuildingTemplateDef.Id to stamp. [JsonPropertyName("template")] public string Template { get; init; } = ""; /// /// Offset from settlement centre in tactical tiles. (0,0) places the /// building's centre on the settlement centre tile. /// [JsonPropertyName("offset")] public int[] Offset { get; init; } = new[] { 0, 0 }; /// /// Optional rotation: 0 / 90 / 180 / 270. Phase 6 M0 ignores; reserved /// so layouts don't have to be re-authored when rotation lands. /// [JsonPropertyName("rotation_deg")] public int RotationDeg { get; init; } = 0; /// /// 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. /// [JsonPropertyName("role_overrides")] public Dictionary RoleOverrides { get; init; } = new(); }