Park/Rides/FlatRides/FerrisWheelRide.cs
using HC3;
using System;

public sealed class FerrisWheelRide : BasicRide
{
	[Property] public GameObject Wheel { get; set; }
	[Property] public List<GameObject> Carts { get; set; } = new();
	[Property, Feature( "Ride" )] public float RotationSpeed { get; set; } = 90.0f; // degrees per second
	[Property, Feature( "Ride" ), Title( "Number of Circuits" ), Inspectable] public int CycleCount { get; set; } = 2;

	private float _rotPerCart => 360.0f / Carts.Count;
	private float _curRotation = 0.0f;
	private int _curCartIdx = 0;
	private Dictionary<int, int> _cartCycles = new();

	protected override void OnUpdate()
	{
		base.OnUpdate();

		if ( !Wheel.IsValid() || Carts.Count == 0 )
			return;

		if ( !RideStarted )
			return;

		float rotDelta = System.MathF.Min( RotationSpeed * Time.Delta, _rotPerCart - _curRotation );
		_curRotation += rotDelta;

		Wheel.LocalRotation *= Rotation.FromAxis( Vector3.Forward, rotDelta );
		OrientCarts();

		if ( _curRotation >= _rotPerCart )
		{
			_curRotation = 0.0f;
			_curCartIdx = (_curCartIdx + 1) % Carts.Count;

			int count = 0;
			if ( _cartCycles.ContainsKey( _curCartIdx ) )
			{
				count = _cartCycles[_curCartIdx]++;
			}

			var cart = Carts[_curCartIdx];
			bool isEmpty = true;
			foreach ( var s in cart.Components.GetAll<SlotMarker>() )
			{
				if ( !s.IsFree() ) { isEmpty = false; break; }
			}

			if ( (isEmpty && QueueingCount > 0) || count >= CycleCount )
			{
				EndRide();
			}
		}
	}

	protected override void OnRideStarted()
	{
		_curRotation = 0f;
		_cartCycles[_curCartIdx] = 0;
	}

	protected override void OnRideEnded()
	{
		UnloadCart( Carts[_curCartIdx] );
	}

	private void UnloadCart( GameObject cart )
	{
		// Collect occupied slots first to avoid mutation during iteration
		var slots = cart.Components.GetAll<SlotMarker>();
		foreach ( var slot in slots )
		{
			if ( !slot.Contents.IsValid() ) continue;
			OnUse( slot.Contents );
			Unload( slot.Contents );
		}
	}

	private void OrientCarts()
	{
		foreach ( var cart in Carts )
		{
			var uprightRotation = Rotation.LookAt( WorldRotation.Forward, WorldRotation.Right );
			cart.WorldRotation = uprightRotation;
		}
	}

	protected override IEnumerable<SlotMarker> GetLoadableSlots()
	{
		if ( Carts.Count < 1 ) return Array.Empty<SlotMarker>();
		return Carts[_curCartIdx].Components.GetAll<SlotMarker>();
	}
}