using System.Text.Json.Serialization;
namespace Theriapolis.Core.Data;
///
/// Phase 7 M0 — a single hand-authored dungeon room. Loaded from
/// Content/Data/room_templates/<type>/*.json.
///
/// A template describes:
/// - The room's footprint in tactical tiles (perimeter walls included).
/// - The 2D ASCII : one char per tactical tile.
/// Legend (per Phase 7 plan §5.1):
/// # wall, . floor, , rubble, D door slot,
/// @ encounter slot, C container slot, T trap slot,
/// P pillar, B brazier, M mosaic (narrative),
/// S stairs (entry/exit only).
/// - Door positions on the perimeter (one entry per D in the grid).
/// - Encounter / container / trap slot positions (which the dungeon
/// populator fills with NPCs and loot).
/// - Optional narrative text surfaced by Scent Literacy / room-clear coda.
/// - The clade that the room — drives the
/// clade-responsive movement multiplier (Phase 7 plan §5.4).
///
/// Templates are designer-friendly to author: edit ASCII art + a couple
/// of metadata blocks.
/// validates grid dimensions vs declared footprint, perimeter walls,
/// and that every D/@/C/T in the grid has
/// a matching slot record.
///
public sealed record RoomTemplateDef
{
[JsonPropertyName("id")]
public string Id { get; init; } = "";
[JsonPropertyName("name")]
public string Name { get; init; } = "";
///
/// Dungeon type the template belongs to: imperium, mine,
/// cult, cave, overgrown. Layout matchers filter
/// templates by type when assembling a dungeon.
///
[JsonPropertyName("type")]
public string Type { get; init; } = "";
///
/// Clade that built or originally inhabited the room. Drives Phase 7
/// clade-responsive movement (a Large PC in a Mustelid tunnel takes 2×
/// movement points). Allowed: canid, felid, mustelid,
/// ursid, cervid, bovid, leporid,
/// imperium, none. Phase-7 Imperium templates use
/// imperium; templates that would be at home in any dungeon use
/// none.
///
[JsonPropertyName("built_by")]
public string BuiltBy { get; init; } = "none";
///
/// Size class — small, medium, large. Used by
/// the layout matcher to pick room mixes appropriate to the dungeon's
/// size band (small dungeons prefer small rooms, etc.).
///
[JsonPropertyName("size_class")]
public string SizeClass { get; init; } = "medium";
///
/// Roles this template is eligible for: entry, transit,
/// narrative, loot, boss, dead-end. A
/// template can be eligible for multiple roles (a "pillar room" can
/// serve as transit OR as a loot stash).
///
[JsonPropertyName("roles_eligible")]
public string[] RolesEligible { get; init; } = Array.Empty();
/// Footprint width in tactical tiles. Includes perimeter walls. Must equal Grid[*].Length.
[JsonPropertyName("footprint_w_tiles")]
public int FootprintWTiles { get; init; } = 1;
/// Footprint height in tactical tiles. Includes perimeter walls. Must equal Grid.Length.
[JsonPropertyName("footprint_h_tiles")]
public int FootprintHTiles { get; init; } = 1;
///
/// 2D ASCII art: one entry per row, one char per tactical tile.
/// Validated for perimeter wall completeness and slot-coordinate
/// matches at content-load time.
///
[JsonPropertyName("grid")]
public string[] Grid { get; init; } = Array.Empty();
/// Door positions in template-local coords (matches D chars in ).
[JsonPropertyName("doors")]
public RoomDoor[] Doors { get; init; } = Array.Empty();
/// Encounter slot positions (matches @ chars).
[JsonPropertyName("encounter_slots")]
public RoomEncounterSlot[] EncounterSlots { get; init; } = Array.Empty();
/// Container slot positions (matches C chars).
[JsonPropertyName("container_slots")]
public RoomContainerSlot[] ContainerSlots { get; init; } = Array.Empty();
/// Trap slot positions (matches T chars). Phase 7 ships only tripwire traps.
[JsonPropertyName("trap_slots")]
public RoomTrapSlot[] TrapSlots { get; init; } = Array.Empty();
/// Decoration placements for non-slot decos (P pillar, B brazier, M mosaic).
[JsonPropertyName("decos")]
public RoomDecoPlacement[] Decos { get; init; } = Array.Empty();
///
/// Environmental-story prose surfaced by Scent Literacy (Phase 6.5 M1)
/// in the InteractionScreen scent-overlay panel and by the dungeon-
/// clear coda. Null/empty for non-narrative templates.
///
[JsonPropertyName("narrative_text")]
public string? NarrativeText { get; init; } = null;
/// Selection weight in layout assembly. Default 1.0.
[JsonPropertyName("weight")]
public float Weight { get; init; } = 1f;
}
public sealed record RoomDoor
{
[JsonPropertyName("x")]
public int X { get; init; }
[JsonPropertyName("y")]
public int Y { get; init; }
/// Compass facing: "N" / "E" / "S" / "W". Door always sits on a perimeter cell.
[JsonPropertyName("facing")]
public string Facing { get; init; } = "S";
///
/// Optional lock difficulty for this door. Empty = unlocked. Allowed:
/// trivial, easy, medium, hard — mapped to
/// LOCK_DC_* constants in code.
///
[JsonPropertyName("lock")]
public string Lock { get; init; } = "";
}
public sealed record RoomEncounterSlot
{
[JsonPropertyName("x")]
public int X { get; init; }
[JsonPropertyName("y")]
public int Y { get; init; }
///
/// Spawn kind: PoiGuard / WildAnimal / Brigand /
/// Boss. Resolved against npc_templates.json's
/// per-dungeon-type spawn-kind override map at populate time.
///
[JsonPropertyName("kind")]
public string Kind { get; init; } = "PoiGuard";
/// Likelihood the slot fires when a layout calls for variability. 1.0 = always.
[JsonPropertyName("weight")]
public float Weight { get; init; } = 1f;
}
public sealed record RoomContainerSlot
{
[JsonPropertyName("x")]
public int X { get; init; }
[JsonPropertyName("y")]
public int Y { get; init; }
///
/// Loot-table band: t1 / t2 / t3. The dungeon's
/// layout maps a band to a real loot-table id at populate time
/// ().
///
[JsonPropertyName("loot_table_band")]
public string LootTableBand { get; init; } = "t1";
/// True when the container is locked (key required, or STR/DEX check).
[JsonPropertyName("locked")]
public bool Locked { get; init; } = false;
/// Optional lock difficulty if : trivial/easy/medium/hard.
[JsonPropertyName("lock")]
public string Lock { get; init; } = "";
}
public sealed record RoomTrapSlot
{
[JsonPropertyName("x")]
public int X { get; init; }
[JsonPropertyName("y")]
public int Y { get; init; }
/// Trap kind. Phase 7 ships only tripwire.
[JsonPropertyName("kind")]
public string Kind { get; init; } = "tripwire";
/// Disarm DC tier: trivial, easy, medium.
[JsonPropertyName("disarm_dc")]
public string DisarmDc { get; init; } = "easy";
}
public sealed record RoomDecoPlacement
{
[JsonPropertyName("x")]
public int X { get; init; }
[JsonPropertyName("y")]
public int Y { get; init; }
///
/// Deco kind name. Allowed: pillar, brazier, mosaic,
/// imperium_statue. Trap / container / door / stairs decos are
/// declared via their respective slot collections, not here.
///
[JsonPropertyName("deco")]
public string Deco { get; init; } = "";
}