SaveData.cs

Data model for game save serialization. Defines SaveData with gameplay counters, inventory, tank state, legacy single-tank fields, and lists of FishSaveData and DecorSaveData used for JSON file persistence.

File Access
namespace NoChillquarium;

/// <summary>
/// Serializable snapshot for FileSystem.Data JSON save.
/// </summary>
public sealed class SaveData
{
	public const int CurrentVersion = 5;
	public const string FileName = "nochill_save.json";

	public int Version { get; set; } = CurrentVersion;
	public double Dogecoin { get; set; }
	public double LifetimeEarned { get; set; }
	public float PlaytimeSeconds { get; set; }
	public float Chaos { get; set; }
	public float Karma { get; set; } = 40f;
	public bool HasWmd { get; set; }
	public bool HasWhale { get; set; }
	public string EndingReached { get; set; } = "";
	public int MethBags { get; set; }
	/// <summary>Bought M80 sticks in inventory (0 until purchased from Shady).</summary>
	public int M80Bags { get; set; }
	/// <summary>Visible glass cracks from failed meth-rush calms (0–5).</summary>
	public int TankCracks { get; set; }
	public List<string> Achievements { get; set; } = new();
	public int LifetimeExplodes { get; set; }
	public int TimesFed { get; set; }
	public int TimesMeth { get; set; }
	public int DecorPlaced { get; set; }
	public List<string> UnlockedFoods { get; set; } = new();
	/// <summary>Empty until the player buys their first food type.</summary>
	public string SelectedFoodId { get; set; } = "";
	public int Syringes { get; set; }
	public int BattleWins { get; set; }
	public int BattleLosses { get; set; }
	public List<string> BattlesBeaten { get; set; } = new();
	/// <summary>Habitat ids claimed as fight prizes (sewage duct, neighbor pool, …).</summary>
	public List<string> PrizeHabitatsWon { get; set; } = new();
	public int SharkKills { get; set; }
	public int SharkEaten { get; set; }
	public bool SharkEverSpawned { get; set; }

	// Dual tanks (v2+)
	public string FreshTankName { get; set; } = "Starter Fresh Tank";
	public string SaltTankName { get; set; } = "Saltwater Tank";
	public string FreshHabitatId { get; set; } = "tank_fresh_1";
	public string SaltHabitatId { get; set; } = "tank_salt_1";
	public int FreshCapacity { get; set; } = TankSim.DefaultCapacity;
	public int SaltCapacity { get; set; } = TankSim.DefaultCapacity;
	public bool SaltUnlocked { get; set; }
	public string ActiveWater { get; set; } = "Fresh";
	public List<FishSaveData> FreshFish { get; set; } = new();
	public List<FishSaveData> SaltFish { get; set; } = new();
	public List<DecorSaveData> FreshDecor { get; set; } = new();
	public List<DecorSaveData> SaltDecor { get; set; } = new();

	// Legacy single-tank fields (v1 continue support)
	public string TankName { get; set; } = "Starter Fresh Tank";
	public string Water { get; set; } = "Fresh";
	public int Capacity { get; set; } = TankSim.DefaultCapacity;
	public List<FishSaveData> Fish { get; set; } = new();
}

public sealed class DecorSaveData
{
	public string DefId { get; set; }
	public float X { get; set; }
	public float Y { get; set; }
}

public sealed class FishSaveData
{
	public string SpeciesId { get; set; }
	/// <summary>Optional player nickname (null/empty = species name).</summary>
	public string Nickname { get; set; }
	public float X { get; set; }
	public float Y { get; set; }
	public float Vx { get; set; }
	public float Vy { get; set; }
	public bool OnMeth { get; set; }
	public float MethTimer { get; set; }
	public float SickTimer { get; set; }
	public float Addiction { get; set; }
	public float WithdrawalTimer { get; set; }
	public float Endurance { get; set; } = 3f;
	public float SpeedStat { get; set; } = 3f;
	public float Agility { get; set; } = 3f;
	public bool Jacked { get; set; }
	public float JackedTimer { get; set; }
	public float Fat { get; set; }
	public bool Stoned { get; set; }
	public float StonedTimer { get; set; }
	/// <summary>Seconds left of post-fight injury lockout (0 = can fight).</summary>
	public float FightInjuryTimer { get; set; }
}