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();
}