relics/RelicRoboAssistant.cs
using Sandbox;
using System.Reflection.PortableExecutable;
using System.Runtime.Versioning;
using System.Threading.Tasks;

public class RelicRoboAssistant : Relic
{
	public override bool ShouldHandleEvent( EventType eventType )
	{
		return eventType == EventType.LevelStart;
	}

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

		await Task.DelayRealtime( 500 );

		List<Card> movedCards = new();

		int count = 0;
		while(count < Level)
		{
			var card = Manager.Instance.GetRandomCard();
			if ( movedCards.Contains( card ) )
				continue;

			var cardMatches = Manager.Instance.Cards.Where( x => x.CardType == card.CardType && x != card ).OrderBy(x => (x.GridPos - card.GridPos).ManhattanLength).ToList();
			if ( cardMatches.Count == 0 )
				continue;

			var match = cardMatches.First();

			if ( Manager.IsAdjacent( card.GridPos, match.GridPos ) )
				continue;

			var path = Manager.Instance.GetPathTo( card.GridPos, match.GridPos );

			if ( path.Count <= 1 )
				continue;

			await Manager.Instance.ShakeCard( card );

			await Task.DelayRealtime( 650 );

			IntVector2 targetGridPos = path.FirstOrDefault();

			var targetCard = Manager.Instance.GetCardAtGridPos( targetGridPos );

			if ( targetCard != null )
				Manager.Instance.PlayCardSfxBetween( "card_move", card, targetCard, volume: 1.1f, pitch: Game.Random.Float( 0.85f, 1.15f ) );
			else
				Manager.Instance.PlayCardSfx( "card_move", card, volume: 1.1f, pitch: Game.Random.Float( 0.85f, 1.15f ) );

			card.MoveToPos( card.LocalPosition.WithZ( Game.Random.Float( 70f, 90f ) ), 0.3f, EasingType.SineOut );
			targetCard?.MoveToPos( targetCard.LocalPosition.WithZ( Game.Random.Float( 70f, 90f ) ), 0.25f, EasingType.SineOut );

			await Task.DelayRealtime( 250 );

			card.MoveToPos( Manager.GetCardPos( targetGridPos ).WithZ( card.LocalPosition.z ), 0.45f, EasingType.SineInOut );
			targetCard?.MoveToPos( Manager.GetCardPos( card.GridPos ).WithZ( targetCard.LocalPosition.z ), 0.45f, EasingType.SineInOut );

			await Task.DelayRealtime( 450 );

			card.MoveToPos( card.LocalPosition.WithZ( Globals.CARD_DEFAULT_HEIGHT + Globals.CARD_ADD_HEIGHT_REVEALED_OR_HOVERED ), 0.2f, EasingType.SineOut );
			targetCard?.MoveToPos( targetCard.LocalPosition.WithZ( Globals.CARD_DEFAULT_HEIGHT ), 0.2f, EasingType.SineOut );

			await Task.DelayRealtime( 200 );

			if ( targetCard != null )
			{
				await Manager.Instance.SwapCardPositions( card, targetCard );
			}
			else
			{
				Manager.Instance.RemoveCardGridPos( card );
				await Manager.Instance.SetCardGridPos( card, targetGridPos );
			}

			card.IsMovementControlled = false;
			if ( targetCard != null )
				targetCard.IsMovementControlled = false;

			await Task.DelayRealtime( 300 );

			movedCards.Add( card );

			count++;
		}
		
		Manager.Instance.PopEventMessage();

		if(movedCards.Count > 0)
			await Manager.Instance.EventHappened( EventType.AfterCardsMoved );
	}

	
}