using Theriapolis.Core.Data;
namespace Theriapolis.Core.Rules.Character;
///
/// Phase 6.5 M4 — runtime state for a hybrid character.
///
/// Hybrids are blended from two parent lineages: a Sire (paternal
/// lineage) and a Dam (maternal lineage), of two different clades.
/// One parent is — the lineage whose physical
/// expression is more visible; this drives Passing eligibility and which
/// clade the PC presents as for casual scent reads.
///
/// The character's own gender is independent of which parent is sire or
/// dam — a male hybrid PC can have a wolf-folk dam and a coyote-folk
/// sire just as readily as the reverse.
///
/// Per theriapolis-rpg-clades.md HYBRID ORIGIN: blend ability mods
/// (one from each parent clade), traits (2 from dominant + 1 from
/// secondary), and inherit *all* universal hybrid detriments — Scent
/// Dysphoria, Illegible Body Language, Social Stigma, Medical
/// Incompatibility (handled by ).
///
/// is toggle-able mid-game; when set, the PC
/// presents as the dominant lineage's clade. Detection by NPCs (Phase 6.5
/// M5) is per-NPC and permanent once revealed.
///
public sealed class HybridState
{
/// Sire (paternal-lineage) clade id, e.g. "canidae".
public string SireClade { get; init; } = "";
/// Sire (paternal-lineage) species id, e.g. "wolf".
public string SireSpecies { get; init; } = "";
/// Dam (maternal-lineage) clade id, e.g. "leporidae".
public string DamClade { get; init; } = "";
/// Dam (maternal-lineage) species id, e.g. "rabbit".
public string DamSpecies { get; init; } = "";
///
/// Which parent's expression is dominant. Drives Passing presentation
/// (the PC scent-reads as this parent's clade) and the trait-split:
/// 2 Clade traits from the dominant parent, 1 from the secondary.
///
public ParentLineage DominantParent { get; init; }
///
/// True when the PC is actively trying to pass as their dominant
/// parent's clade. Toggles on the character sheet; consulted by
/// Phase 6.5 M5 passing-detection rolls.
///
public bool PassingActive { get; set; }
///
/// Phase 6.5 M5 — currently-active scent mask tier (if any). The mask
/// suppresses scent-based detection per its tier. Phase 6.5 M5 ships
/// the static tier flag; Phase 8's clock model adds time-based
/// expiry alongside daily wear.
///
public ScentMaskTier ActiveMaskTier { get; set; } = ScentMaskTier.None;
///
/// NPC ids who have personally detected this PC is hybrid. Permanent
/// once added — disabling Passing later doesn't undo the discovery
/// for that specific NPC. Phase 6.5 M5 populates this; M4 reserves it
/// in the schema so save round-trip works pre- and post-M5.
///
public HashSet NpcsWhoKnow { get; } = new();
///
/// Convenience: which clade the PC presents as for casual scent reads
/// (used by Phase 6.5 M5 passing logic and Phase 7 dialogue gates).
/// Returns the dominant parent's clade id.
///
public string PresentingCladeId =>
DominantParent == ParentLineage.Sire ? SireClade : DamClade;
///
/// Convenience: which species the PC presents as. Same logic as
/// .
///
public string PresentingSpeciesId =>
DominantParent == ParentLineage.Sire ? SireSpecies : DamSpecies;
}
///
/// Phase 6.5 M4 — which parent in a hybrid PC's lineage is the
/// dominant/secondary expression. Sire = paternal lineage, Dam = maternal
/// lineage; the choice is OOC (no gender semantics for the character
/// themselves, just for the parents' lineages).
///
public enum ParentLineage : byte
{
Sire = 0,
Dam = 1,
}
///
/// Phase 6.5 M5 — scent-mask tier suppressing hybrid detection. Maps to
/// the consumable items in items.json:
/// None — no mask active
/// Basic — scent_mask_basic; advantage on PC Deception roll
/// Military — scent_mask_military; auto-suppresses scent detection
/// DeepCover — scent_mask_deep_cover; auto-suppresses, even Superior Scent
///
/// Per the Phase 6.5 plan §4.7. Phase 8's clock + rest model adds
/// time-based expiry; M5 carries the tier as static state.
///
public enum ScentMaskTier : byte
{
None = 0,
Basic = 1,
Military = 2,
DeepCover = 3,
}