diff --git a/app/src/main/java/org/prolibertate/games/ui/common/Components.kt b/app/src/main/java/org/prolibertate/games/ui/common/Components.kt index 3808e66..8ef3193 100644 --- a/app/src/main/java/org/prolibertate/games/ui/common/Components.kt +++ b/app/src/main/java/org/prolibertate/games/ui/common/Components.kt @@ -41,6 +41,12 @@ fun PlayingCardView( width: Dp = 64.dp, selected: Boolean = false, enabled: Boolean = true, + /** + * Short note printed on the face, for when the rank and suit alone do not + * say what the card does — a Sequence jack being the obvious case, since + * one-eyed and two-eyed jacks are only distinguishable by their artwork. + */ + caption: String? = null, onClick: (() -> Unit)? = null, ) { val ink = if (card.suit.isRed) CardRed else CardBlack @@ -61,6 +67,8 @@ fun PlayingCardView( ), contentAlignment = Alignment.Center, ) { + // Shrink the pips slightly when a caption has to share the face. + val pipScale = if (caption == null) 0.34f else 0.28f Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, @@ -69,13 +77,22 @@ fun PlayingCardView( text = card.rank.short, color = ink, fontWeight = FontWeight.Bold, - fontSize = (width.value * 0.34f).sp, + fontSize = (width.value * pipScale).sp, ) Text( text = card.suit.symbol, color = ink, - fontSize = (width.value * 0.34f).sp, + fontSize = (width.value * pipScale).sp, ) + if (caption != null) { + Text( + text = caption, + color = ink, + fontWeight = FontWeight.Bold, + fontSize = (width.value * 0.145f).sp, + maxLines = 1, + ) + } } } } diff --git a/app/src/main/java/org/prolibertate/games/ui/game/SequenceScreen.kt b/app/src/main/java/org/prolibertate/games/ui/game/SequenceScreen.kt index 6843f97..afa4a21 100644 --- a/app/src/main/java/org/prolibertate/games/ui/game/SequenceScreen.kt +++ b/app/src/main/java/org/prolibertate/games/ui/game/SequenceScreen.kt @@ -35,6 +35,8 @@ import androidx.compose.ui.unit.sp import org.prolibertate.games.game.cards.Card import org.prolibertate.games.game.sequence.BOARD_SIZE import org.prolibertate.games.game.sequence.ExchangeDeadCard +import org.prolibertate.games.game.sequence.isOneEyedJack +import org.prolibertate.games.game.sequence.isTwoEyedJack import org.prolibertate.games.game.sequence.NO_TEAM import org.prolibertate.games.game.sequence.PlaceChip import org.prolibertate.games.game.sequence.RemoveChip @@ -54,6 +56,17 @@ import org.prolibertate.games.ui.theme.TeamColours */ private val HighlightAmber = Color(0xFFFFC107) +/** + * What a jack does, printed on its face. On a real deck this is carried by the + * artwork — a jack shown in profile has one eye and removes a chip, one shown + * face-on has two and is wild — which a rank-and-suit card cannot convey. + */ +private fun jackCaption(card: Card): String? = when { + isTwoEyedJack(card) -> "WILD" + isOneEyedJack(card) -> "REMOVE" + else -> null +} + /** * The Sequence board. * @@ -294,6 +307,9 @@ private fun HandStrip( width = cardWidth, selected = card == selected, enabled = card in playable, + // A jack's power comes from its artwork, which these cards + // do not have, so spell it out on the face instead. + caption = jackCaption(card), onClick = { val dead = exchanges[card] if (dead != null) onExchange(dead) else onSelect(card) @@ -301,9 +317,18 @@ private fun HandStrip( ) } } - selected?.let { + selected?.let { card -> Text( - text = "Tap a highlighted square to play ${it.label}.", + text = when { + isTwoEyedJack(card) -> + "${card.label} is wild — tap any empty square." + + isOneEyedJack(card) -> + "${card.label} removes a chip — tap an opponent's, " + + "as long as it isn't part of a finished sequence." + + else -> "Tap a highlighted square to play ${card.label}." + }, style = MaterialTheme.typography.bodySmall, ) } diff --git a/docs/RULES-sequence.md b/docs/RULES-sequence.md index b09c36d..b68a82c 100644 --- a/docs/RULES-sequence.md +++ b/docs/RULES-sequence.md @@ -53,6 +53,11 @@ Play one card and place a chip on a matching empty square, then draw. - **Two-eyed jacks** (♦ and ♣) are wild: place a chip on any empty square. - **One-eyed jacks** (♥ and ♠) remove one opposing chip — but never a chip that is part of a completed sequence, and never your own team's chip. + +On a physical deck the difference is carried by the artwork: a jack drawn in +profile shows one eye, a jack drawn face-on shows two. These cards are drawn as +rank and suit only, so a jack in hand is captioned **WILD** or **REMOVE** +instead. - **Dead card — *toggle*, on by default.** If both squares printed with your card are already occupied, you may discard it and draw a replacement. This does not cost your turn, and you may do it once per turn.