namespace Theriapolis.Core.Persistence; /// /// Plain-data snapshot of a for /// the save layer. Kept as primitive fields + arrays so the persistence /// codec doesn't pull MessagePack attributes onto the live model. /// /// Items / equipped slots reference content by id (string); the loader /// re-resolves them against the current set /// after world content reloads. /// public sealed class PlayerCharacterState { public string CladeId { get; set; } = ""; public string SpeciesId { get; set; } = ""; public string ClassId { get; set; } = ""; public string BackgroundId { get; set; } = ""; // Final ability scores (post clade + species mods). public byte STR { get; set; } public byte DEX { get; set; } public byte CON { get; set; } public byte INT { get; set; } public byte WIS { get; set; } public byte CHA { get; set; } public int Level { get; set; } = 1; public int Xp { get; set; } = 0; public int MaxHp { get; set; } public int CurrentHp { get; set; } public int ExhaustionLevel { get; set; } = 0; // Phase 5 M6 additions — backward-compat handled by EndOfStream check in SaveCodec.ReadCharacter. public string FightingStyle { get; set; } = ""; public int RageUsesRemaining { get; set; } = 2; // Phase 6 M3 — coin balance (Fangs are Theriapolis's universal currency). public int CurrencyFang { get; set; } = 0; // Phase 6.5 M0 — levelling state. /// /// Subclass id chosen at level 3 (or whatever /// is). Empty pre-L3. /// public string SubclassId { get; set; } = ""; /// Feature ids learned across all level-ups, in unlock order. public string[] LearnedFeatureIds { get; set; } = Array.Empty(); /// Append-only per-level-up history (deltas, not post-state). public LevelUpRecordState[] LevelUpHistory { get; set; } = Array.Empty(); // Phase 6.5 M4 — hybrid-character genealogy. Null for purebred PCs. public HybridStateSnapshot? Hybrid { get; set; } /// Skill ids stored as enum byte values for compactness. public byte[] SkillProficiencies { get; set; } = Array.Empty(); /// Active conditions stored as enum byte values. public byte[] Conditions { get; set; } = Array.Empty(); /// Inventory stacks — references to ItemDef.Id with quantity + condition + optional equip slot. public InventoryItemState[] Inventory { get; set; } = Array.Empty(); } /// /// Phase 6.5 M0 — one entry in . /// Plain-data round-trip of . /// public sealed class LevelUpRecordState { public int Level { get; set; } public int HpGained { get; set; } public bool HpWasAveraged { get; set; } public int HpHitDieResult { get; set; } /// Empty when no subclass was chosen at this level (i.e. anything but L3). public string SubclassChosen { get; set; } = ""; /// ASI ability ids stored as enum byte values; same length as . public byte[] AsiKeys { get; set; } = Array.Empty(); public int[] AsiValues { get; set; } = Array.Empty(); public string[] FeaturesUnlocked { get; set; } = Array.Empty(); } /// /// Phase 6.5 M4 — flat round-trip record for . /// public sealed class HybridStateSnapshot { public string SireClade { get; set; } = ""; public string SireSpecies { get; set; } = ""; public string DamClade { get; set; } = ""; public string DamSpecies { get; set; } = ""; /// 0 = Sire, 1 = Dam (matches byte values). public byte DominantParent { get; set; } = 0; public bool PassingActive { get; set; } = false; /// Per-NPC discovery list — populated in Phase 6.5 M5. public int[] NpcsWhoKnow { get; set; } = Array.Empty(); /// Active scent-mask tier (Phase 6.5 M5). 0 = none. public byte ActiveMaskTier { get; set; } = 0; } /// One stack in . public sealed class InventoryItemState { public string ItemId { get; set; } = ""; public int Qty { get; set; } = 1; public int Condition { get; set; } = 100; /// Null if this stack is bagged. Otherwise the EquipSlot enum byte value. public byte? EquippedAt { get; set; } }