Game/SimVersion.cs
namespace BlockParty;

/// <summary>
/// Version of the deterministic simulation, stamped into every recorded run
/// (<see cref="RunData.SimVersion"/>). SEPARATE from <see cref="Leaderboard.LEADERBOARD_VERSION"/>:
/// bump THIS for any behaviour change to the fixed-step sim (physics, block/character logic, Rng
/// draw order, input decoding). Post-release such a change ships together with a version gate at
/// the changed site (<c>if ( Stage.SimVersion &gt;= Sim.SOME_FIX ) newBehaviour else oldBehaviour</c>)
/// so replays recorded on older versions keep playing back through the old path: the sim runs at
/// the RUN's version (<see cref="GameManager.CurrentRunSimVersion"/> — the recorded one for a replay,
/// <see cref="VERSION"/> for a live run), and <see cref="RunData.CanReplay"/> accepts any version in
/// [<see cref="MIN_REPLAY_VERSION"/>, <see cref="VERSION"/>]. replay_verify against the release-blessed
/// baselines proves the old paths still reproduce bit-for-bit.
/// Bump LEADERBOARD_VERSION only to start fresh boards (which also re-rolls the daily layouts).
/// </summary>
public static class Sim
{
	public const int VERSION = 43;

	/// <summary>Oldest recorded sim version this build still replays (the release version — every
	/// later change is gated). Raise only to retire gates.</summary>
	public const int MIN_REPLAY_VERSION = 40;

	// --- gated fixes (first version whose sim has the new behaviour) ---------------------------

	/// <summary>Riding a DESCENDING block re-presses its freshly popped top (post phase-up / spike
	/// retract) like a static or rising one — the ride glue's carry counts as closing motion in
	/// Unpenetrate's press gate.</summary>
	public const int RIDE_CARRY_PRESS = 41;

	/// <summary>No ground jump / Shifter surface jump / Flipper invert off a live-spiked floor, and no
	/// wall jump / Spring wall charge off a live-spiked side face. The floor and hug flags are 1px
	/// proximity probes while obstacle/arena spikes kill only on penetration, so a slow approach
	/// (hug-slide, hover run-out, drift into a wall) could launch away from inside that window before
	/// touching the teeth (Player.LaunchFloorIsSpiked / WallLaunchIsSpiked).</summary>
	public const int NO_JUMP_OFF_SPIKES = 42;

	/// <summary>A Mimic's phase-2 disguise is never StraightLaser or SquidPierce
	/// (GameStage.MimicPhase2Excluded): Shrinks the pick's candidate list, so the
	/// Rng.Int range (and thus the pick) differs from v42.</summary>
	public const int MIMIC_P2_EXCLUSIONS = 43;
}