using System.Text.Json.Serialization; namespace Theriapolis.Core.Data; /// /// Phase 6 M1 — definition of a friendly/neutral resident NPC inhabiting a /// settlement. Two flavours, both loaded from resident_templates.json: /// /// 1. **Generic** (Named == false) — matches by /// prefix. picks the highest-weight /// generic whose RoleTag equals the building-role tag (e.g. "innkeeper", /// "shopkeeper", "guard"). /// /// 2. **Named** (Named == true) — matches by exact /// (e.g. "millhaven.innkeeper"). Used when a settlement preset's /// role_overrides qualifies a building role with a specific /// anchor-prefixed tag, locking that NPC to a hand-authored species, /// name, and bias profile. /// /// Combat stats are minimal in M1 — residents are non-combatants by /// default. They have a token / in case the /// player attacks them; engagement promotes them to a derived combatant /// using the existing -style stat block. /// public sealed record ResidentTemplateDef { [JsonPropertyName("id")] public string Id { get; init; } = ""; /// /// The role tag this template matches. Generic templates use bare /// occupations ("innkeeper"); named templates use anchor-prefixed /// "settlement.role" ids ("millhaven.innkeeper"). /// [JsonPropertyName("role_tag")] public string RoleTag { get; init; } = ""; /// True when this template is hand-authored for a specific named NPC. Always wins over generic when role_tag matches. [JsonPropertyName("named")] public bool Named { get; init; } = false; /// Display name shown in dialogue + tooltip. Empty for generics → resolved from . [JsonPropertyName("name")] public string Name { get; init; } = ""; /// Clade id (e.g. "canidae"). Required for named templates; generics may leave empty to roll from settlement biome. [JsonPropertyName("clade")] public string Clade { get; init; } = ""; /// Species id (e.g. "wolf"). Required for named; generics roll from clade. [JsonPropertyName("species")] public string Species { get; init; } = ""; /// Bias profile id this NPC carries (matches BiasProfileDef.Id). [JsonPropertyName("bias_profile")] public string BiasProfile { get; init; } = "URBAN_PROGRESSIVE"; /// Faction affiliation id (matches FactionDef.Id), or empty for unaffiliated. [JsonPropertyName("faction")] public string Faction { get; init; } = ""; /// Dialogue tree id (matches dialogues/*.json id). Empty → fall back to a generic-by-role placeholder. [JsonPropertyName("dialogue")] public string Dialogue { get; init; } = ""; /// "friendly" or "neutral". Defaults to friendly. Hostile residents go through the npc_templates path instead. [JsonPropertyName("default_allegiance")] public string DefaultAllegiance { get; init; } = "friendly"; /// Stat block for combat fallback. Defaults are commoner-ish (HP 8, AC 10). [JsonPropertyName("hp")] public int Hp { get; init; } = 8; [JsonPropertyName("ac")] public int Ac { get; init; } = 10; [JsonPropertyName("ability_scores")] public Dictionary AbilityScores { get; init; } = new(); /// Selection weight when multiple generic templates match the same role tag. [JsonPropertyName("weight")] public float Weight { get; init; } = 1f; }