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>
111 lines
4.8 KiB
C#
111 lines
4.8 KiB
C#
namespace Theriapolis.Core.Persistence;
|
|
|
|
/// <summary>
|
|
/// Plain-data snapshot of a <see cref="Rules.Character.Character"/> 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 <see cref="Data.ItemDef"/> set
|
|
/// after world content reloads.
|
|
/// </summary>
|
|
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.
|
|
/// <summary>
|
|
/// Subclass id chosen at level 3 (or whatever
|
|
/// <see cref="C.SUBCLASS_SELECTION_LEVEL"/> is). Empty pre-L3.
|
|
/// </summary>
|
|
public string SubclassId { get; set; } = "";
|
|
|
|
/// <summary>Feature ids learned across all level-ups, in unlock order.</summary>
|
|
public string[] LearnedFeatureIds { get; set; } = Array.Empty<string>();
|
|
|
|
/// <summary>Append-only per-level-up history (deltas, not post-state).</summary>
|
|
public LevelUpRecordState[] LevelUpHistory { get; set; } = Array.Empty<LevelUpRecordState>();
|
|
|
|
// Phase 6.5 M4 — hybrid-character genealogy. Null for purebred PCs.
|
|
public HybridStateSnapshot? Hybrid { get; set; }
|
|
|
|
/// <summary>Skill ids stored as enum byte values for compactness.</summary>
|
|
public byte[] SkillProficiencies { get; set; } = Array.Empty<byte>();
|
|
|
|
/// <summary>Active conditions stored as enum byte values.</summary>
|
|
public byte[] Conditions { get; set; } = Array.Empty<byte>();
|
|
|
|
/// <summary>Inventory stacks — references to ItemDef.Id with quantity + condition + optional equip slot.</summary>
|
|
public InventoryItemState[] Inventory { get; set; } = Array.Empty<InventoryItemState>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Phase 6.5 M0 — one entry in <see cref="PlayerCharacterState.LevelUpHistory"/>.
|
|
/// Plain-data round-trip of <see cref="Rules.Character.LevelUpRecord"/>.
|
|
/// </summary>
|
|
public sealed class LevelUpRecordState
|
|
{
|
|
public int Level { get; set; }
|
|
public int HpGained { get; set; }
|
|
public bool HpWasAveraged { get; set; }
|
|
public int HpHitDieResult { get; set; }
|
|
/// <summary>Empty when no subclass was chosen at this level (i.e. anything but L3).</summary>
|
|
public string SubclassChosen { get; set; } = "";
|
|
/// <summary>ASI ability ids stored as enum byte values; same length as <see cref="AsiValues"/>.</summary>
|
|
public byte[] AsiKeys { get; set; } = Array.Empty<byte>();
|
|
public int[] AsiValues { get; set; } = Array.Empty<int>();
|
|
public string[] FeaturesUnlocked { get; set; } = Array.Empty<string>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Phase 6.5 M4 — flat round-trip record for <see cref="Rules.Character.HybridState"/>.
|
|
/// </summary>
|
|
public sealed class HybridStateSnapshot
|
|
{
|
|
public string SireClade { get; set; } = "";
|
|
public string SireSpecies { get; set; } = "";
|
|
public string DamClade { get; set; } = "";
|
|
public string DamSpecies { get; set; } = "";
|
|
/// <summary>0 = Sire, 1 = Dam (matches <see cref="Rules.Character.ParentLineage"/> byte values).</summary>
|
|
public byte DominantParent { get; set; } = 0;
|
|
public bool PassingActive { get; set; } = false;
|
|
/// <summary>Per-NPC discovery list — populated in Phase 6.5 M5.</summary>
|
|
public int[] NpcsWhoKnow { get; set; } = Array.Empty<int>();
|
|
/// <summary>Active scent-mask tier (Phase 6.5 M5). 0 = none.</summary>
|
|
public byte ActiveMaskTier { get; set; } = 0;
|
|
}
|
|
|
|
/// <summary>One stack in <see cref="PlayerCharacterState.Inventory"/>.</summary>
|
|
public sealed class InventoryItemState
|
|
{
|
|
public string ItemId { get; set; } = "";
|
|
public int Qty { get; set; } = 1;
|
|
public int Condition { get; set; } = 100;
|
|
/// <summary>Null if this stack is bagged. Otherwise the EquipSlot enum byte value.</summary>
|
|
public byte? EquippedAt { get; set; }
|
|
}
|