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