Cards/CardFace.cs

A value type that describes a drawable card face. It stores identifier, corner/center text, colors, gameplay value, pip count and label, and includes a helper to create a standard playing-card face from Rank and Suit.

namespace CardGames;

/// <summary>
/// Describes a single drawable card face. A <see cref="DeckDefinition"/> resolves to an ordered
/// list of these; a runtime <see cref="Card"/> is just an index into it. Generic on purpose so the
/// same data drives a poker deck, an Uno-style colour deck or anything custom - and the fields are
/// <c>[Property]</c> so a deck's custom card list is editable in the inspector.
/// </summary>
public struct CardFace
{
	/// <summary>
	/// Stable identifier for a card, e.g. "AS", "10H".
	/// </summary>
	[KeyProperty] public string Key { get; set; }

	/// <summary>
	/// Small text in the corners, e.g. "A", "10", "K", or an Uno number.
	/// </summary>
	[Property] public string Corner { get; set; }

	/// <summary>
	/// Large symbol drawn in the centre, e.g. a suit glyph or an Uno icon.
	/// </summary>
	[Property] public string Center { get; set; }

	/// <summary>
	/// Ink colour for the corner/centre marks (red/black for a standard deck, white on a colour card).
	/// </summary>
	[Property] public Color Accent { get; set; }

	/// <summary>
	/// Per-card face colour. Defaults to transparent, which means "use the deck's <see cref="DeckDefinition.FaceColor"/>".
	/// Set it for colour-on-card decks (e.g. Uno red/green/blue/yellow).
	/// </summary>
	[Property] public Color Background { get; set; }

	/// <summary>
	/// Generic gameplay value. For a standard deck this is the rank ordinal (1-13).
	/// </summary>
	[Property] public int Value { get; set; }

	/// <summary>
	/// Number of pips to lay out in the centre. 0 for face/custom cards.
	/// </summary>
	[Property] public int Pips { get; set; }

	/// <summary>
	/// Human readable name, e.g. "Ace of Spades". Handy for logs and tooltips.
	/// </summary>
	[Property] public string Label { get; set; }

	/// <summary>
	/// True if this card overrides the deck's face colour with its own <see cref="Background"/>.
	/// </summary>
	public readonly bool HasBackground => Background.a > 0f;

	public static CardFace FromStandard( Rank rank, Suit suit ) => new()
	{
		Key = $"{rank.Short()}{suit.ToString()[0]}", // e.g. "AS", "10H", "KC"
		Corner = rank.Short(),
		Center = suit.Glyph(),
		Accent = suit.IsRed() ? Color.Red : Color.Black,
		Value = (int)rank,
		Pips = rank.PipCount(),
		Label = $"{rank} of {suit}"
		// Background left transparent → uses the deck's FaceColor (white).
	};
}