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

public class CardJumpingSpider : Card
{
	public override bool IsAlive => true;

	public override bool ValidateStartingGridPos()
	{
		if ( Manager.Instance.IsGridPosCorner( GridPos ) )
			return true;

		IntVector2 newGridPos;
		int rand = Game.Random.Int( 0, 3 );
		switch(rand)
		{
			case 0: default:
				newGridPos = new IntVector2( 0, 0 );
				break;
			case 1:
				newGridPos = new IntVector2( 0, Manager.Instance.GridHeight - 1 );
				break;
			case 2:
				newGridPos = new IntVector2( Manager.Instance.GridWidth - 1, 0 );
				break;
			case 3:
				newGridPos = new IntVector2( Manager.Instance.GridWidth - 1, Manager.Instance.GridHeight - 1 );
				break;
		}

		Manager.Instance.SwapCardPositionsNonAsync(this, Manager.Instance.GetCardAtGridPos(newGridPos));

		return false;
	}

	public override bool ShouldHandleEvent( EventType eventType )
	{
		return eventType == EventType.Mismatch && Manager.Instance.ChosenCards.Contains( this ) && !Manager.Instance.IsMismatchALockedMatch;
	}

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

		var validCards = Manager.Instance.Cards.Where(x => !Manager.Instance.ChosenCards.Contains( x ) ).ToList();
		validCards.Shuffle();

		var otherCard = validCards.FirstOrDefault();

		await Task.DelayRealtime( 500 );

		Manager.Instance.HideCard( this );
		Manager.Instance.PlayCardSfx( "card_flip", this, volume: 0.7f, pitch: Game.Random.Float( 0.65f, 0.75f ) );

		await Task.DelayRealtime( 400 );

		Manager.Instance.PlayCardSfx( "spider", this, volume: 1f, pitch: Game.Random.Float( 0.95f, 1.1f ) );

		await Task.DelayRealtime( 100 );

		Manager.Instance.ShowOverlayColor( new Color( 0.1f, 0.1f, 0.05f ), 1.5f );

		await Task.DelayRealtime( 300 );

		await Manager.Instance.SwapCardPositions( this, otherCard, instant: true );

		await Task.DelayRealtime( 500 );

		Manager.Instance.PopEventMessage();

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

	public override string GetEventText( EventType eventType )
	{
		return "❌Mismatch: swaps with an unknown card";
	}
}