diff --git a/src/components/Card/Card.module.scss b/src/components/Card/Card.module.scss index a289ac6..16f67af 100644 --- a/src/components/Card/Card.module.scss +++ b/src/components/Card/Card.module.scss @@ -20,6 +20,17 @@ justify-content: center; container-type: inline-size; } + +.CardHighlight { + -webkit-animation: glow 1s ease-in-out infinite alternate; + -moz-animation: glow 1s ease-in-out infinite alternate; + animation: glow 1s ease-in-out infinite alternate; +} + +.CardDim { + opacity: 0.7; +} + .CardContent { text-align: center; overflow-wrap: break-word; @@ -40,3 +51,14 @@ transform: translateX(0); } } + +@keyframes glow { + from { + box-shadow: 0 0 2px #fff, 0 0 4px #fff, 0 0 6px #84b893, 0 0 8px #84b893, 0 0 10px #84b893, 0 0 12px #84b893, + 0 0 14px #84b893; + } + to { + box-shadow: 0 0 2px #fff, 0 0 4px #fff, 0 0 6px #1e5e31, 0 0 8px #1e5e31, 0 0 10px #1e5e31, 0 0 12px #1e5e31, + 0 0 14px #1e5e31; + } +} diff --git a/src/components/Card/Card.tsx b/src/components/Card/Card.tsx index a722912..38645f8 100644 --- a/src/components/Card/Card.tsx +++ b/src/components/Card/Card.tsx @@ -6,9 +6,12 @@ import { import styles from "./Card.module.scss"; -export interface CardProps extends CardObject {} +export type CardEffect = "highlight" | "dim" | "none"; +export interface CardProps extends CardObject { + effect: CardEffect; +} -function Card({ rank, suit, facing }: CardProps) { +function Card({ rank, suit, facing, effect }: CardProps) { const suitData = CardSuitMetadataMap[suit]; const rankData = CardRankMetadataMap[rank]; @@ -20,9 +23,15 @@ function Card({ rank, suit, facing }: CardProps) { content = ["?"]; } + const cardClasses = [ + styles.Card, + effect === "dim" && styles.CardDim, + effect === "highlight" && styles.CardHighlight, + ].join(" "); + return (
-
+
{content}
diff --git a/src/components/CardRow/CardRow.tsx b/src/components/CardRow/CardRow.tsx index 135d78d..29df9ce 100644 --- a/src/components/CardRow/CardRow.tsx +++ b/src/components/CardRow/CardRow.tsx @@ -4,27 +4,35 @@ import { CardObject } from "../Card"; import styles from "./CardRow.module.scss"; import React from "react"; +import { CardEffect } from "../Card/Card"; export interface CardRowProps { cardOwner: Participant; cards: CardObject[]; + effect: CardEffect; children?: React.ReactNode; } -const CardRow = (props: CardRowProps) => { +const CardRow = ({ cardOwner, cards, effect, children }: CardRowProps) => { return (
- {props.cardOwner} Cards + {cardOwner} Cards {/* Pretty hacky, but the settings icon is passed into this row as a child element */} - {props.children} + {children}
- {props.cards.map(({ facing, rank, suit }, i) => ( - + {cards.map(({ facing, rank, suit }, i) => ( + ))}
diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index c163cca..9c3e6f4 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -2,12 +2,13 @@ import { useState } from "react"; import CardRow from "../CardRow"; import InfoHud from "../InfoHud"; import YesNoPopUp from "../YesNoPopUp"; -import { useGame } from "."; +import { Participant, useGame } from "."; import { ScoreBoardRow } from "../ScoreBoard"; import { useGameSettingsStore } from "../../stores/gameSettingsStore"; import styles from "./Table.module.scss"; import SettingsButton from "../SettingsButton"; +import { CardEffect } from "../Card/Card"; const Table = ({ hide = false }: { hide?: boolean }) => { const game = useGame(); @@ -93,14 +94,27 @@ const Table = ({ hide = false }: { hide?: boolean }) => { ]; } + function getCardEffect(cardOwner: Participant): CardEffect { + if (game.winner === "none") return "none"; + return cardOwner === game.winner ? "highlight" : "dim"; + } + return (
{showHitWarning && getHitWarning()} {showStickWarning && getStickWarning()} - + - + ("WaitingForStart"); const [outcome, setOutcome] = useState(null); + const [winner, setWinner] = useState("none"); const deck = useDeck(); const player = useCardPile(); @@ -68,7 +77,7 @@ export function useGame() { let timeout: NodeJS.Timeout | undefined; if (dealer.bust) { - setResult("Dealer bust, dealer wins!", "Player"); + setResult("Dealer bust, player wins!", "Player"); } else if (dealer.fiveCardTrick) { setResult("Dealer wins with a five card trick!", "Dealer"); } @@ -133,6 +142,7 @@ export function useGame() { */ function setup() { setOutcome(null); + setWinner("none"); deck.init(); player.setCards([]); @@ -196,6 +206,7 @@ export function useGame() { function setResult(outcomeText: string, winner?: Participant | null): void { setState("GameOver"); setOutcome(outcomeText); + setWinner(winner ?? "none"); winner && stats.updateWinnerStats(winner); } @@ -223,6 +234,11 @@ export function useGame() { * Statistics about the games played during this session. */ stats, + + /** + * The participant who won the round, if any. + */ + winner, setup, startDealerRound, getParticipantScore, diff --git a/src/utilities/deckUtilities.test.ts b/src/utilities/deckUtilities.test.ts index a4205f0..69df4af 100644 --- a/src/utilities/deckUtilities.test.ts +++ b/src/utilities/deckUtilities.test.ts @@ -10,7 +10,7 @@ describe("deckUtilities", () => { cards: [ { card: { facing: "Up", rank: "Ace", suit: "Club" }, - rankRelativeValueUsed: Math.min( + rankGlobalValueUsed: Math.min( ...CardRankMetadataMap["Ace"].relativeValues ), rankValueUsed: Math.min(...CardRankMetadataMap["Ace"].values), @@ -22,7 +22,7 @@ describe("deckUtilities", () => { cards: [ { card: { facing: "Up", rank: "Ace", suit: "Diamond" }, - rankRelativeValueUsed: Math.min( + rankGlobalValueUsed: Math.min( ...CardRankMetadataMap["Ace"].relativeValues ), rankValueUsed: Math.min(...CardRankMetadataMap["Ace"].values), @@ -51,7 +51,7 @@ describe("deckUtilities", () => { it("Should return Dealer when dealer has more cards than player", () => { dealerHand.cards.push({ card: { facing: "Up", rank: "Eight", suit: "Diamond" }, - rankRelativeValueUsed: 8, + rankGlobalValueUsed: 8, rankValueUsed: 8, }); dealerHand.score = playerHand.score; @@ -63,7 +63,7 @@ describe("deckUtilities", () => { it("Should return Player when player has more cards than player", () => { playerHand.cards.push({ card: { facing: "Up", rank: "Eight", suit: "Diamond" }, - rankRelativeValueUsed: 8, + rankGlobalValueUsed: 8, rankValueUsed: 8, }); playerHand.score = dealerHand.score; @@ -77,12 +77,12 @@ describe("deckUtilities", () => { it("Should return Dealer when dealers high card is greater than players", () => { dealerHand.cards.push({ card: { facing: "Up", rank: "Eight", suit: "Diamond" }, - rankRelativeValueUsed: 8, + rankGlobalValueUsed: 8, rankValueUsed: 8, }); playerHand.cards.push({ card: { facing: "Up", rank: "Seven", suit: "Diamond" }, - rankRelativeValueUsed: 7, + rankGlobalValueUsed: 7, rankValueUsed: 7, }); dealerHand.score = playerHand.score; @@ -94,12 +94,12 @@ describe("deckUtilities", () => { it("Should return Player when player has more cards than player", () => { dealerHand.cards.push({ card: { facing: "Up", rank: "Seven", suit: "Diamond" }, - rankRelativeValueUsed: 7, + rankGlobalValueUsed: 7, rankValueUsed: 7, }); playerHand.cards.push({ card: { facing: "Up", rank: "Eight", suit: "Diamond" }, - rankRelativeValueUsed: 8, + rankGlobalValueUsed: 8, rankValueUsed: 8, }); playerHand.score = dealerHand.score; diff --git a/src/utilities/deckUtilities.ts b/src/utilities/deckUtilities.ts index 18a2f71..1fc85f6 100644 --- a/src/utilities/deckUtilities.ts +++ b/src/utilities/deckUtilities.ts @@ -100,7 +100,7 @@ export const generateDeck = ( export interface CardValue { card: CardObject; rankValueUsed: number; - rankRelativeValueUsed: number; + rankGlobalValueUsed: number; } export interface BestHand { score: number; @@ -125,12 +125,12 @@ export const calculateBestHand = (cards: CardObject[]): BestHand => { } const cardValue = Math.max(...CardRankMetadataMap[card.rank].values); - const cardRelativeValue = Math.max( + const cardGlobalValue = Math.max( ...CardRankMetadataMap[card.rank].relativeValues ); bestHand.cards.push({ card, - rankRelativeValueUsed: cardRelativeValue, + rankGlobalValueUsed: cardGlobalValue, rankValueUsed: cardValue, }); bestHand.score += cardValue; @@ -197,17 +197,15 @@ export const determineWinner = ( }; const getHighestCardValue = (cards: CardValue[]) => { - return cards.sort((a, b) => b.rankValueUsed - a.rankValueUsed)[0]; + return cards.sort((a, b) => b.rankGlobalValueUsed - a.rankGlobalValueUsed)[0]; }; const getHighCardWinner = ( playerCards: CardValue[], dealerCards: CardValue[] ): GameResult | null => { - const playerHighCard = getHighestCardValue(playerCards).rankValueUsed; - console.log("playerHighCard", playerHighCard); - const dealerHighCard = getHighestCardValue(dealerCards).rankValueUsed; - console.log("dealerHighCard", dealerHighCard); + const playerHighCard = getHighestCardValue(playerCards).rankGlobalValueUsed; + const dealerHighCard = getHighestCardValue(dealerCards).rankGlobalValueUsed; const winner = getPlayerWithHighestValue(playerHighCard, dealerHighCard); if (!winner) return null;