cards/CardAncientScroll.cs
using Sandbox;
using System.Threading.Tasks;

public class CardAncientScroll : Card
{
	public override bool ShouldHandleEvent( EventType eventType )
	{
		return eventType == EventType.Match && Manager.Instance.ChosenCards[1] == this;
	}

	public override async Task HandleEventAsync( EventType eventType )
	{
		if ( Manager.Instance.Cards.Count <= 2 )
			return;

		Manager.Instance.PushEventMessage( this, eventType );

		Manager.Instance.PlayCardSfx( "ancient_scroll", this, volume: 1f, pitch: Game.Random.Float( 0.9f, 1f ) );

		await Task.DelayRealtime( 800 );

		for ( int y = Manager.Instance.GridHeight - 1; y >= 0; y-- )
		{
			for ( int x = 0; x < Manager.Instance.GridWidth; x++ )
			{
				var card = Manager.Instance.GetCardAtGridPos( x, y );
				if ( card != null && !card.IsRevealed )
				{
					await Manager.Instance.RevealCard( card );
					Manager.Instance.PlayCardSfx( "card_flip", card, pitch: Game.Random.Float( 0.9f, 1.1f ) );

					await Task.DelayRealtime( 50 );
				}
			}
		}

		await Task.DelayRealtime( 1500 );

		Manager.Instance.PlayCardSfx( "ancient_scroll", this, volume: 0.8f, pitch: Game.Random.Float( 0.7f, 0.75f ) );

		await Task.DelayRealtime( 500 );

		for ( int y = Manager.Instance.GridHeight - 1; y >= 0; y-- )
		{
			for ( int x = 0; x < Manager.Instance.GridWidth; x++ )
			{
				var card = Manager.Instance.GetCardAtGridPos( x, y );
				if ( card != null && !Manager.Instance.ChosenCards.Contains(card))
				{
					Manager.Instance.HideCard( card );
					Manager.Instance.PlayCardSfx( "card_flip", card, volume: 0.7f, pitch: Game.Random.Float( 0.65f, 0.75f ) );

					await Task.DelayRealtime( 50 );
				}
			}
		}

		await Task.DelayRealtime( 500 );

		Manager.Instance.PopEventMessage();

		Manager.Instance.AddStatus( "StatusAncientScroll" );
	}
}

public class StatusAncientScroll : StatusEffect
{
	private int _numTurnsRemaining = 2;

	public override bool ShouldHandleEvent( EventType eventType )
	{
		if ( eventType == EventType.TurnStart )
		{
			_numTurnsRemaining--;
			return _numTurnsRemaining == 0;
		}

		return false;
	}

	public override async Task HandleEventAsync( EventType eventType )
	{
		Manager.Instance.PushEventMessage( this, eventType );

		await Task.DelayRealtime( 500 );

		// todo: sfx not playing at center?
		var centerPos = Manager.Instance.CenterPos;
		Manager.Instance.PlaySfx( "ancient_scroll", new Vector3( centerPos.x, centerPos.y, Manager.Instance.Camera.WorldPosition.z - 100f), volume: 1f, pitch: Game.Random.Float( 0.9f, 1f ) );

		await Task.DelayRealtime( 800 );

		// todo: sfx
		for ( int y = Manager.Instance.GridHeight - 1; y >= 0; y-- )
		{
			for ( int x = 0; x < Manager.Instance.GridWidth; x++ )
			{
				var card = Manager.Instance.GetCardAtGridPos( x, y );
				if ( card != null )
				{
					card.MoveToPos( centerPos.WithZ( 80f ), 0.5f, EasingType.QuadOut );

					await Task.DelayRealtime( 50 );
				}
			}
		}

		await Task.DelayRealtime( 800 );

		foreach ( Card card in Manager.Instance.Cards )
			Manager.Instance.RemoveCardGridPos( card );

		List<IntVector2> allGridPositions = new();
		for ( int y = Manager.Instance.GridHeight - 1; y >= 0; y-- )
		{
			for ( int x = 0; x < Manager.Instance.GridWidth; x++ )
			{
				allGridPositions.Add( new IntVector2( x, y ) );
			}
		}

		var cards = Manager.Instance.Cards.ToList();
		cards.Shuffle();

		int count = 0;
		foreach ( Card card in cards )
		{
			card.MoveToPos( Manager.GetCardPos( allGridPositions[count] ), 0.15f, EasingType.QuadOut );
			Manager.Instance.PlaySfx( "card_move", new Vector3( centerPos.x, centerPos.y, Manager.Instance.Camera.WorldPosition.z - 100f ), volume: 0.6f, pitch: Game.Random.Float( 1.2f, 1.4f ) );

			await Task.DelayRealtime( 60 );

			count++;
		}

		await Task.DelayRealtime( 200 );

		count = 0;
		foreach ( Card card in cards )
		{
			await Manager.Instance.SetCardGridPos( card, allGridPositions[count] );
			card.IsMovementControlled = false;
			count++;
		}

		await Task.DelayRealtime( 200 );

		Manager.Instance.PopEventMessage();

		Manager.Instance.RemoveStatus( this );

		await Manager.Instance.EventHappened( EventType.AfterCardsMoved );
	}

	public override string GetEventIcon( EventType eventType )
	{
		return "textures/scroll.png";
	}

	public override string GetEventText( EventType eventType )
	{
		return "Shuffle all cards";
	}
}