using Theriapolis.Core.Util; namespace Theriapolis.Core.Entities; /// /// Player actor. Phase 4 keeps the field set deliberately small — just enough /// to position, save, and reload a single human-controlled character. Stats, /// inventory, and class data are added in Phase 5. /// public sealed class PlayerActor : Actor { public string Name { get; set; } = "Wanderer"; /// Highest settlement tier the player has actually visited (1 = capital). public int HighestTierReached { get; set; } = 5; /// Set of discovered settlement / PoI ids. Drives slot-picker labels and Phase 7+ map UI. public HashSet DiscoveredPoiIds { get; } = new(); /// Snapshot used by SaveCodec; mutated by RestoreState. public PlayerActorState CaptureState() => new() { Id = Id, Name = Name, PositionX = Position.X, PositionY = Position.Y, FacingAngleRad = FacingAngleRad, SpeedWorldPxPerSec = SpeedWorldPxPerSec, HighestTierReached = HighestTierReached, DiscoveredPoiIds = DiscoveredPoiIds.ToArray(), }; public void RestoreState(PlayerActorState s) { Name = s.Name; Position = new Vec2(s.PositionX, s.PositionY); FacingAngleRad = s.FacingAngleRad; SpeedWorldPxPerSec = s.SpeedWorldPxPerSec; HighestTierReached = s.HighestTierReached; DiscoveredPoiIds.Clear(); foreach (int id in s.DiscoveredPoiIds) DiscoveredPoiIds.Add(id); } } /// /// Plain serializable snapshot of a . /// Kept as a struct of primitive fields so the persistence layer doesn't need /// MessagePack attributes on the live object — keeps Core dependency-free for /// modules that don't yet care about saves. /// public sealed class PlayerActorState { public int Id; public string Name = ""; public float PositionX; public float PositionY; public float FacingAngleRad; public float SpeedWorldPxPerSec; public int HighestTierReached; public int[] DiscoveredPoiIds = Array.Empty(); }