Files
Christopher Wiebe b451f83174 Initial commit: Theriapolis baseline at port/godot branch point
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>
2026-04-30 20:40:51 -07:00

83 lines
3.6 KiB
C#

using Theriapolis.Core.Entities;
using Theriapolis.Core.Tactical;
using Theriapolis.Core.Time;
namespace Theriapolis.Core.Persistence;
/// <summary>
/// All save-worthy state outside the seed-derivable world. Phase 4 fills the
/// player, clock, chunk deltas, and world-tile deltas; the other fields are
/// reserved for Phase 5/6 so adding them later doesn't require a schema bump.
/// </summary>
public sealed class SaveBody
{
public PlayerActorState Player { get; set; } = new();
public WorldClockState Clock { get; set; } = new();
/// <summary>
/// Phase 5: full character snapshot (clade, species, class, abilities,
/// HP, inventory). Null on Phase-4 saves; the loader treats null as a
/// migration-failed signal and refuses the save.
/// </summary>
public PlayerCharacterState? PlayerCharacter { get; set; }
/// <summary>
/// Phase 5 M5: per-chunk NPC roster delta (which spawn indices have died).
/// Empty on a fresh save; populated as the player kills NPCs.
/// </summary>
public NpcRosterState NpcRoster { get; set; } = new();
/// <summary>
/// Phase 5 M5: present only when the player saved mid-combat. On load,
/// PlayScreen re-creates the encounter from this snapshot and pushes
/// CombatHUDScreen directly without going through the title.
/// </summary>
public EncounterState? ActiveEncounter { get; set; }
/// <summary>Per-chunk player-modification overlay.</summary>
public Dictionary<ChunkCoord, ChunkDelta> ModifiedChunks { get; set; } = new();
/// <summary>Sparse per-world-tile changes (e.g. burned settlement).</summary>
public List<WorldTileDelta> ModifiedWorldTiles { get; set; } = new();
// ── Reserved for later phases ────────────────────────────────────────
// Empty containers so save schema doesn't need a migration when each
// subsystem comes online.
public Dictionary<string, int> Flags { get; set; } = new();
/// <summary>v5 placeholder. Phase 6 M2 superseded by <see cref="ReputationState"/>.</summary>
public Dictionary<int, int> Factions { get; set; } = new();
/// <summary>v5 placeholder. Phase 6 M4 superseded by <see cref="QuestEngineState"/>.</summary>
public List<int> QuestState { get; set; } = new();
/// <summary>v5 placeholder. Phase 6 M2 superseded by <see cref="ReputationState"/>.</summary>
public Dictionary<string, int> Reputation { get; set; } = new();
public List<int> DiscoveredPoiIds { get; set; } = new();
/// <summary>
/// Phase 6 M2 — full reputation snapshot (faction standings, per-NPC
/// personal dispositions, recent ledger). Empty on a fresh game; the
/// V5→V6 migration leaves this empty too (Phase-5 saves never
/// accumulated rep state).
/// </summary>
public ReputationSnapshot ReputationState { get; set; } = new();
/// <summary>
/// Phase 6 M4 — quest engine snapshot. Empty before any quest
/// activates. Named <c>QuestEngineState</c> to avoid colliding with
/// the v5 placeholder <see cref="QuestState"/> dictionary.
/// </summary>
public QuestSnapshot QuestEngineState { get; set; } = new();
}
/// <summary>One world-tile cell that diverged from worldgen baseline.</summary>
public readonly struct WorldTileDelta
{
public readonly ushort X;
public readonly ushort Y;
public readonly byte NewBiome;
public readonly ushort NewFeatures;
public WorldTileDelta(int x, int y, byte biome, ushort features)
{
X = (ushort)x; Y = (ushort)y; NewBiome = biome; NewFeatures = features;
}
}