aded Tarokka deck

This commit is contained in:
Gavin McDonald
2025-04-10 11:23:59 -04:00
parent f373782538
commit 5fc5fcd486
70 changed files with 1148 additions and 963 deletions

View File

@@ -41,10 +41,10 @@ export default function GamePage() {
} : undefined; } : undefined;
}, [gameID]); }, [gameID]);
const flipCard = (cardID: string) => { const flipCard = (cardIndex: number) => {
const flip: ClientUpdate = { const flip: ClientUpdate = {
gameID, gameID,
cardID, cardIndex,
}; };
socket.emit('flip-card', flip); socket.emit('flip-card', flip);
@@ -54,22 +54,16 @@ export default function GamePage() {
<main className="min-h-screen flex flex-col items-center justify-center gap-4"> <main className="min-h-screen flex flex-col items-center justify-center gap-4">
<h1 className="text-2xl font-bold">Game ID: {gameID}</h1> <h1 className="text-2xl font-bold">Game ID: {gameID}</h1>
<div className="grid grid-cols-3 gap-4"> <div className="grid grid-cols-3 grid-rows-3 gap-4 w-fit mx-auto">
<div className="col-start-2"> {Array.from({ length: 9 }).map((_, i) => {
<Card id={cards[0].id} flipped={cards[0].flipped} onFlip={flipCard} /> const cardIndex = [1, 3, 4, 5, 7].indexOf(i);
</div>
<div className="col-start-1"> return (
<Card id={cards[1].id} flipped={cards[1].flipped} onFlip={flipCard} /> <div key={i} className="aspect-[2/3] w-24}">
</div> {cardIndex !== -1 && <Card card={cards[cardIndex]} flipAction={() => flipCard(cardIndex)} />}
<div>
<Card id={cards[2].id} flipped={cards[2].flipped} onFlip={flipCard} />
</div>
<div>
<Card id={cards[3].id} flipped={cards[3].flipped} onFlip={flipCard} />
</div>
<div className="col-start-2">
<Card id={cards[4].id} flipped={cards[4].flipped} onFlip={flipCard} />
</div> </div>
)
})}
</div> </div>
</main> </main>
) : null; ) : null;

View File

@@ -1,27 +1,22 @@
'use client'; 'use client';
import { StandardGameCard, TarokkaGameCard } from "@/types";
type CardProps = { type CardProps = {
id: string; card: StandardGameCard | TarokkaGameCard;
flipped: boolean; flipAction: () => void;
onFlip: (id: string) => void;
}; };
export default function Card({ id, flipped, onFlip }: CardProps) { export default function Card({ card: { aria, url }, flipAction }: CardProps) {
return ( return (
<div <div
className={`w-24 h-32 flex items-center justify-center cursor-pointer`} className={`w-24 h-32 flex items-center justify-center cursor-pointer`}
onClick={() => onFlip(id)} onClick={flipAction}
> >
{flipped ? (
<img <img
src={`/cards/${id}.svg`} src={url}
alt={aria}
/> />
) : (
<img
src="/cards/1B.svg"
/>
)
}
</div> </div>
); );
} }

View File

@@ -1,453 +0,0 @@
const cards = [
{
"id": "1B",
"back": true,
"face": false,
"joker": false,
"suit": null,
"url": "/cards/1B.svg"
},
{
"id": "2B",
"back": true,
"face": false,
"joker": false,
"suit": null,
"url": "/cards/2B.svg"
},
{
"id": "1J",
"back": false,
"face": false,
"joker": true,
"suit": null,
"url": "/cards/1J.svg"
},
{
"id": "2J",
"back": false,
"face": false,
"joker": true,
"suit": null,
"url": "/cards/2J.svg"
},
{
"id": "AC",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/AC.svg"
},
{
"id": "AD",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/AD.svg"
},
{
"id": "AH",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/AH.svg"
},
{
"id": "AS",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/AS.svg"
},
{
"id": "2C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/2C.svg"
},
{
"id": "2D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/2D.svg"
},
{
"id": "2H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/2H.svg"
},
{
"id": "2S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/2S.svg"
},
{
"id": "3C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/3C.svg"
},
{
"id": "3D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/3D.svg"
},
{
"id": "3H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/3H.svg"
},
{
"id": "3S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/3S.svg"
},
{
"id": "4C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/4C.svg"
},
{
"id": "4D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/4D.svg"
},
{
"id": "4H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/4H.svg"
},
{
"id": "4S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/4S.svg"
},
{
"id": "5C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/5C.svg"
},
{
"id": "5D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/5D.svg"
},
{
"id": "5H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/5H.svg"
},
{
"id": "5S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/5S.svg"
},
{
"id": "6C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/6C.svg"
},
{
"id": "6D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/6D.svg"
},
{
"id": "6H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/6H.svg"
},
{
"id": "6S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/6S.svg"
},
{
"id": "7C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/7C.svg"
},
{
"id": "7D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/7D.svg"
},
{
"id": "7H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/7H.svg"
},
{
"id": "7S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/7S.svg"
},
{
"id": "8C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/8C.svg"
},
{
"id": "8D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/8D.svg"
},
{
"id": "8H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/8H.svg"
},
{
"id": "8S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/8S.svg"
},
{
"id": "9C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/9C.svg"
},
{
"id": "9D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/9D.svg"
},
{
"id": "9H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/9H.svg"
},
{
"id": "9S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/9S.svg"
},
{
"id": "10C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/10C.svg"
},
{
"id": "10D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/10D.svg"
},
{
"id": "10H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/10H.svg"
},
{
"id": "10S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/10S.svg"
},
{
"id": "JC",
"back": false,
"face": true,
"joker": false,
"suit": "Clubs",
"url": "/cards/JC.svg"
},
{
"id": "JD",
"back": false,
"face": true,
"joker": false,
"suit": "Diamonds",
"url": "/cards/JD.svg"
},
{
"id": "JH",
"back": false,
"face": true,
"joker": false,
"suit": "Hearts",
"url": "/cards/JH.svg"
},
{
"id": "JS",
"back": false,
"face": true,
"joker": false,
"suit": "Spades",
"url": "/cards/JS.svg"
},
{
"id": "KC",
"back": false,
"face": true,
"joker": false,
"suit": "Clubs",
"url": "/cards/KC.svg"
},
{
"id": "KD",
"back": false,
"face": true,
"joker": false,
"suit": "Diamonds",
"url": "/cards/KD.svg"
},
{
"id": "KH",
"back": false,
"face": true,
"joker": false,
"suit": "Hearts",
"url": "/cards/KH.svg"
},
{
"id": "KS",
"back": false,
"face": true,
"joker": false,
"suit": "Spades",
"url": "/cards/KS.svg"
},
{
"id": "QC",
"back": false,
"face": true,
"joker": false,
"suit": "Clubs",
"url": "/cards/QC.svg"
},
{
"id": "QD",
"back": false,
"face": true,
"joker": false,
"suit": "Diamonds",
"url": "/cards/QD.svg"
},
{
"id": "QH",
"back": false,
"face": true,
"joker": false,
"suit": "Hearts",
"url": "/cards/QH.svg"
},
{
"id": "QS",
"back": false,
"face": true,
"joker": false,
"suit": "Spades",
"url": "/cards/QS.svg"
}
];
export default cards;

View File

@@ -1,454 +0,0 @@
import { CardImage } from '@/types';
const cards: CardImage[] = [
{
"id": "1B",
"back": true,
"face": false,
"joker": false,
"suit": null,
"url": "/cards/1B.svg"
},
{
"id": "2B",
"back": true,
"face": false,
"joker": false,
"suit": null,
"url": "/cards/2B.svg"
},
{
"id": "1J",
"back": false,
"face": false,
"joker": true,
"suit": null,
"url": "/cards/1J.svg"
},
{
"id": "2J",
"back": false,
"face": false,
"joker": true,
"suit": null,
"url": "/cards/2J.svg"
},
{
"id": "AC",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/AC.svg"
},
{
"id": "AD",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/AD.svg"
},
{
"id": "AH",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/AH.svg"
},
{
"id": "AS",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/AS.svg"
},
{
"id": "2C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/2C.svg"
},
{
"id": "2D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/2D.svg"
},
{
"id": "2H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/2H.svg"
},
{
"id": "2S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/2S.svg"
},
{
"id": "3C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/3C.svg"
},
{
"id": "3D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/3D.svg"
},
{
"id": "3H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/3H.svg"
},
{
"id": "3S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/3S.svg"
},
{
"id": "4C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/4C.svg"
},
{
"id": "4D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/4D.svg"
},
{
"id": "4H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/4H.svg"
},
{
"id": "4S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/4S.svg"
},
{
"id": "5C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/5C.svg"
},
{
"id": "5D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/5D.svg"
},
{
"id": "5H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/5H.svg"
},
{
"id": "5S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/5S.svg"
},
{
"id": "6C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/6C.svg"
},
{
"id": "6D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/6D.svg"
},
{
"id": "6H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/6H.svg"
},
{
"id": "6S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/6S.svg"
},
{
"id": "7C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/7C.svg"
},
{
"id": "7D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/7D.svg"
},
{
"id": "7H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/7H.svg"
},
{
"id": "7S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/7S.svg"
},
{
"id": "8C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/8C.svg"
},
{
"id": "8D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/8D.svg"
},
{
"id": "8H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/8H.svg"
},
{
"id": "8S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/8S.svg"
},
{
"id": "9C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/9C.svg"
},
{
"id": "9D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/9D.svg"
},
{
"id": "9H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/9H.svg"
},
{
"id": "9S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/9S.svg"
},
{
"id": "10C",
"back": false,
"face": false,
"joker": false,
"suit": "Clubs",
"url": "/cards/10C.svg"
},
{
"id": "10D",
"back": false,
"face": false,
"joker": false,
"suit": "Diamonds",
"url": "/cards/10D.svg"
},
{
"id": "10H",
"back": false,
"face": false,
"joker": false,
"suit": "Hearts",
"url": "/cards/10H.svg"
},
{
"id": "10S",
"back": false,
"face": false,
"joker": false,
"suit": "Spades",
"url": "/cards/10S.svg"
},
{
"id": "JC",
"back": false,
"face": true,
"joker": false,
"suit": "Clubs",
"url": "/cards/JC.svg"
},
{
"id": "JD",
"back": false,
"face": true,
"joker": false,
"suit": "Diamonds",
"url": "/cards/JD.svg"
},
{
"id": "JH",
"back": false,
"face": true,
"joker": false,
"suit": "Hearts",
"url": "/cards/JH.svg"
},
{
"id": "JS",
"back": false,
"face": true,
"joker": false,
"suit": "Spades",
"url": "/cards/JS.svg"
},
{
"id": "KC",
"back": false,
"face": true,
"joker": false,
"suit": "Clubs",
"url": "/cards/KC.svg"
},
{
"id": "KD",
"back": false,
"face": true,
"joker": false,
"suit": "Diamonds",
"url": "/cards/KD.svg"
},
{
"id": "KH",
"back": false,
"face": true,
"joker": false,
"suit": "Hearts",
"url": "/cards/KH.svg"
},
{
"id": "KS",
"back": false,
"face": true,
"joker": false,
"suit": "Spades",
"url": "/cards/KS.svg"
},
{
"id": "QC",
"back": false,
"face": true,
"joker": false,
"suit": "Clubs",
"url": "/cards/QC.svg"
},
{
"id": "QD",
"back": false,
"face": true,
"joker": false,
"suit": "Diamonds",
"url": "/cards/QD.svg"
},
{
"id": "QH",
"back": false,
"face": true,
"joker": false,
"suit": "Hearts",
"url": "/cards/QH.svg"
},
{
"id": "QS",
"back": false,
"face": true,
"joker": false,
"suit": "Spades",
"url": "/cards/QS.svg"
}
];
export default cards;

510
constants/standardCards.ts Normal file
View File

@@ -0,0 +1,510 @@
import { StandardCard } from '@/types';
const cards: StandardCard[] = [
{
id: '1B',
aria: '',
back: true,
face: false,
joker: false,
suit: null,
url: '/cards/1B.svg'
},
{
id: '2B',
aria: '',
back: true,
face: false,
joker: false,
suit: null,
url: '/cards/2B.svg'
},
{
id: '1J',
aria: '',
back: false,
face: false,
joker: true,
suit: null,
url: '/cards/1J.svg'
},
{
id: '2J',
aria: '',
back: false,
face: false,
joker: true,
suit: null,
url: '/cards/2J.svg'
},
{
id: 'AC',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Clubs',
url: '/cards/AC.svg'
},
{
id: 'AD',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Diamonds',
url: '/cards/AD.svg'
},
{
id: 'AH',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Hearts',
url: '/cards/AH.svg'
},
{
id: 'AS',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Spades',
url: '/cards/AS.svg'
},
{
id: '2C',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Clubs',
url: '/cards/2C.svg'
},
{
id: '2D',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Diamonds',
url: '/cards/2D.svg'
},
{
id: '2H',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Hearts',
url: '/cards/2H.svg'
},
{
id: '2S',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Spades',
url: '/cards/2S.svg'
},
{
id: '3C',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Clubs',
url: '/cards/3C.svg'
},
{
id: '3D',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Diamonds',
url: '/cards/3D.svg'
},
{
id: '3H',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Hearts',
url: '/cards/3H.svg'
},
{
id: '3S',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Spades',
url: '/cards/3S.svg'
},
{
id: '4C',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Clubs',
url: '/cards/4C.svg'
},
{
id: '4D',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Diamonds',
url: '/cards/4D.svg'
},
{
id: '4H',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Hearts',
url: '/cards/4H.svg'
},
{
id: '4S',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Spades',
url: '/cards/4S.svg'
},
{
id: '5C',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Clubs',
url: '/cards/5C.svg'
},
{
id: '5D',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Diamonds',
url: '/cards/5D.svg'
},
{
id: '5H',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Hearts',
url: '/cards/5H.svg'
},
{
id: '5S',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Spades',
url: '/cards/5S.svg'
},
{
id: '6C',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Clubs',
url: '/cards/6C.svg'
},
{
id: '6D',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Diamonds',
url: '/cards/6D.svg'
},
{
id: '6H',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Hearts',
url: '/cards/6H.svg'
},
{
id: '6S',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Spades',
url: '/cards/6S.svg'
},
{
id: '7C',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Clubs',
url: '/cards/7C.svg'
},
{
id: '7D',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Diamonds',
url: '/cards/7D.svg'
},
{
id: '7H',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Hearts',
url: '/cards/7H.svg'
},
{
id: '7S',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Spades',
url: '/cards/7S.svg'
},
{
id: '8C',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Clubs',
url: '/cards/8C.svg'
},
{
id: '8D',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Diamonds',
url: '/cards/8D.svg'
},
{
id: '8H',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Hearts',
url: '/cards/8H.svg'
},
{
id: '8S',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Spades',
url: '/cards/8S.svg'
},
{
id: '9C',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Clubs',
url: '/cards/9C.svg'
},
{
id: '9D',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Diamonds',
url: '/cards/9D.svg'
},
{
id: '9H',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Hearts',
url: '/cards/9H.svg'
},
{
id: '9S',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Spades',
url: '/cards/9S.svg'
},
{
id: '10C',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Clubs',
url: '/cards/10C.svg'
},
{
id: '10D',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Diamonds',
url: '/cards/10D.svg'
},
{
id: '10H',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Hearts',
url: '/cards/10H.svg'
},
{
id: '10S',
aria: '',
back: false,
face: false,
joker: false,
suit: 'Spades',
url: '/cards/10S.svg'
},
{
id: 'JC',
aria: '',
back: false,
face: true,
joker: false,
suit: 'Clubs',
url: '/cards/JC.svg'
},
{
id: 'JD',
aria: '',
back: false,
face: true,
joker: false,
suit: 'Diamonds',
url: '/cards/JD.svg'
},
{
id: 'JH',
aria: '',
back: false,
face: true,
joker: false,
suit: 'Hearts',
url: '/cards/JH.svg'
},
{
id: 'JS',
aria: '',
back: false,
face: true,
joker: false,
suit: 'Spades',
url: '/cards/JS.svg'
},
{
id: 'KC',
aria: '',
back: false,
face: true,
joker: false,
suit: 'Clubs',
url: '/cards/KC.svg'
},
{
id: 'KD',
aria: '',
back: false,
face: true,
joker: false,
suit: 'Diamonds',
url: '/cards/KD.svg'
},
{
id: 'KH',
aria: '',
back: false,
face: true,
joker: false,
suit: 'Hearts',
url: '/cards/KH.svg'
},
{
id: 'KS',
aria: '',
back: false,
face: true,
joker: false,
suit: 'Spades',
url: '/cards/KS.svg'
},
{
id: 'QC',
aria: '',
back: false,
face: true,
joker: false,
suit: 'Clubs',
url: '/cards/QC.svg'
},
{
id: 'QD',
aria: '',
back: false,
face: true,
joker: false,
suit: 'Diamonds',
url: '/cards/QD.svg'
},
{
id: 'QH',
aria: '',
back: false,
face: true,
joker: false,
suit: 'Hearts',
url: '/cards/QH.svg'
},
{
id: 'QS',
aria: '',
back: false,
face: true,
joker: false,
suit: 'Spades',
url: '/cards/QS.svg'
}
];
export default cards;

557
constants/tarokkaCards.ts Normal file
View File

@@ -0,0 +1,557 @@
import { TarokkaCard } from '@/types';
const tarokkaCards: TarokkaCard[] = [
{
id: 'Back',
name: 'Card Back',
card: 'Back of card',
description: 'Back of card',
aria: 'Back of card',
back: true,
suit: null,
url: '/img/tarokka/Back.jpg',
},
{
id: 'Coins_01_Swashbuckler',
name: 'Swashbuckler',
card: 'One of Coins',
description: 'Those who like money yet give it up freely; likable rogues and rapscallions',
aria: 'Coins 01 Swashbuckler',
back: false,
suit: 'Coins',
url: '/img/tarokka/Coins_01_Swashbuckler.jpeg',
},
{
id: 'Coins_02_Philanthropist',
name: 'Philanthropist',
card: 'Two of Coins',
description: 'Charity and giving on a grand scale; those who use wealth to fight evil and sickness',
aria: 'Coins 02 Philanthropist',
back: false,
suit: 'Coins',
url: '/img/tarokka/Coins_02_Philanthropist.jpeg',
},
{
id: 'Coins_03_Trader',
name: 'Trader',
card: 'Three of Coins',
description: 'Commerce; smuggling and black markets; fair and equitable trades',
aria: 'Coins 03 Trader',
back: false,
suit: 'Coins',
url: '/img/tarokka/Coins_03_Trader.jpeg',
},
{
id: 'Coins_04_Merchant',
name: 'Merchant',
card: 'Four of Coins',
description: 'A rare commodity or business opportunity; deceitful or dangerous business transactions',
aria: 'Coins 04 Merchant',
back: false,
suit: 'Coins',
url: '/img/tarokka/Coins_04_Merchant.jpeg',
},
{
id: 'Coins_05_GuildMember',
name: 'Guild Member',
card: 'Five of Coins',
description: 'Like-minded individuals joined together in a common goal; pride in one\'s work',
aria: 'Coins 05 Guild Member',
back: false,
suit: 'Coins',
url: '/img/tarokka/Coins_05_GuildMember.jpeg',
},
{
id: 'Coins_06_Beggar',
name: 'Beggar',
card: 'Six of Coins',
description: 'Sudden change in economic status or fortune',
aria: 'Coins 06 Beggar',
back: false,
suit: 'Coins',
url: '/img/tarokka/Coins_06_Beggar.jpeg',
},
{
id: 'Coins_07_Thief',
name: 'Thief',
card: 'Seven of Coins',
description: 'Those who steal or burgle; a loss of property, beauty, innocence, friendship, or reputation',
aria: 'Coins 07 Thief',
back: false,
suit: 'Coins',
url: '/img/tarokka/Coins_07_Thief.jpeg',
},
{
id: 'Coins_08_TaxCollector',
name: 'Tax Collector',
card: 'Eight of Coins',
description: 'Corruption; honesty in an otherwise corrupt government or organization',
aria: 'Coins 08 Tax Collector',
back: false,
suit: 'Coins',
url: '/img/tarokka/Coins_08_TaxCollector.png',
},
{
id: 'Coins_09_Miser',
name: 'Miser',
card: 'Nine of Coins',
description: 'Hoarded wealth; those who are irreversibly unhappy or who think money is meaningless',
aria: 'Coins 09 Miser',
back: false,
suit: 'Coins',
url: '/img/tarokka/Coins_09_Miser.jpeg',
},
{
id: 'Coins_10_Rogue',
name: 'Rogue',
card: 'Master of Coins',
description: 'Anyone for whom money is important; those who believe money is the key to their success',
aria: 'Coins 10 Rogue',
back: false,
suit: 'Coins',
url: '/img/tarokka/Coins_10_Rogue.jpeg',
},
{
id: 'Glyphs_01_Monk',
name: 'Monk',
card: 'One of Glyphs',
description: 'Serenity; inner strength and self-reliance; supreme confidence bereft of arrogance',
aria: 'Glyphs 01 Monk',
back: false,
suit: 'Glyphs',
url: '/img/tarokka/Glyphs_01_Monk.jpeg',
},
{
id: 'Glyphs_02_Missionary',
name: 'Missionary',
card: 'Two of Glyphs',
description: 'Those who spread wisdom and faith to others; warnings of the spread of fear and ignorance',
aria: 'Glyphs 02 Missionary',
back: false,
suit: 'Glyphs',
url: '/img/tarokka/Glyphs_02_Missionary.jpeg',
},
{
id: 'Glyphs_03_Healer',
name: 'Healer',
card: 'Three of Glyphs',
description: 'Healing; a contagious illness, disease, or curse; those who practice the healing arts',
aria: 'Glyphs 03 Healer',
back: false,
suit: 'Glyphs',
url: '/img/tarokka/Glyphs_03_Healer.jpeg',
},
{
id: 'Glyphs_04_Shepherd',
name: 'Shepherd',
card: 'Four of Glyphs',
description: 'Those who protect others; one who bears a burden far too great to be shouldered alone',
aria: 'Glyphs 04 Shepherd',
back: false,
suit: 'Glyphs',
url: '/img/tarokka/Glyphs_04_Shepherd.jpeg',
},
{
id: 'Glyphs_05_Druid',
name: 'Druid',
card: 'Five of Glyphs',
description: 'The ambivalence and cruelty of nature and those who feel drawn to it; inner turmoil',
aria: 'Glyphs 05 Druid',
back: false,
suit: 'Glyphs',
url: '/img/tarokka/Glyphs_05_Druid.jpeg',
},
{
id: 'Glyphs_06_Anarchist',
name: 'Anarchist',
card: 'Six of Glyphs',
description: 'A fundamental change brought on by one whose beliefs are being put to the test',
aria: 'Glyphs 06 Anarchist',
back: false,
suit: 'Glyphs',
url: '/img/tarokka/Glyphs_06_Anarchist.jpeg',
},
{
id: 'Glyphs_07_Charlatan',
name: 'Charlatan',
card: 'Seven of Glyphs',
description: 'Liars; those who profess to believe one thing but actually believe another',
aria: 'Glyphs 07 Charlatan',
back: false,
suit: 'Glyphs',
url: '/img/tarokka/Glyphs_07_Charlatan.jpeg',
},
{
id: 'Glyphs_08_Bishop',
name: 'Bishop',
card: 'Eight of Glyphs',
description: 'Strict adherence to a code or a belief; those who plot, plan, and scheme',
aria: 'Glyphs 08 Bishop',
back: false,
suit: 'Glyphs',
url: '/img/tarokka/Glyphs_08_Bishop.jpeg',
},
{
id: 'Glyphs_09_Traitor',
name: 'Traitor',
card: 'Nine of Glyphs',
description: 'Betrayal by someone close and trusted; a weakening or loss of faith',
aria: 'Glyphs 09 Traitor',
back: false,
suit: 'Glyphs',
url: '/img/tarokka/Glyphs_09_Traitor.jpeg',
},
{
id: 'Glyphs_10_Priest',
name: 'Priest',
card: 'Master of Glyphs',
description: 'Enlightenment; those who follow a deity, a system of values, or a higher purpose',
aria: 'Glyphs 10 Priest',
back: false,
suit: 'Glyphs',
url: '/img/tarokka/Glyphs_10_Priest.jpeg',
},
{
id: 'Stars_01_Transmuter',
name: 'Transmuter',
card: 'One of Stars',
description: 'A new discovery; the coming of unexpected things; unforeseen consequences and chaos',
aria: 'Stars 01 Transmuter',
back: false,
suit: 'Stars',
url: '/img/tarokka/Stars_01_Transmuter.jpeg',
},
{
id: 'Stars_02_Diviner',
name: 'Diviner',
card: 'Two of Stars',
description: 'The pursuit of knowledge tempered by wisdom; truth and honesty; sages and prophecy',
aria: 'Stars 02 Diviner',
back: false,
suit: 'Stars',
url: '/img/tarokka/Stars_02_Diviner.jpeg',
},
{
id: 'Stars_03_Enchanter',
name: 'Enchanter',
card: 'Three of Stars',
description: 'Inner turmoil that comes from confusion, fear of failure, or false information',
aria: 'Stars 03 Enchanter',
back: false,
suit: 'Stars',
url: '/img/tarokka/Stars_03_Enchanter.png',
},
{
id: 'Stars_04_Abjurer',
name: 'Abjurer',
card: 'Four of Stars',
description: 'Those guided by logic and reasoning; warns of an overlooked clue or piece of information',
aria: 'Stars 04 Abjurer',
back: false,
suit: 'Stars',
url: '/img/tarokka/Stars_04_Abjurer.jpeg',
},
{
id: 'Stars_05_Elementalist',
name: 'Elementalist',
card: 'Five of Stars',
description: 'The triumph of nature over civilization; natural disasters and bountiful harvests',
aria: 'Stars 05 Elementalist',
back: false,
suit: 'Stars',
url: '/img/tarokka/Stars_05_Elementalist.jpeg',
},
{
id: 'Stars_06_Evoker',
name: 'Evoker',
card: 'Six of Stars',
description: 'Magical or supernatural power that can\'t be controlled; magic for destructive ends',
aria: 'Stars 06 Evoker',
back: false,
suit: 'Stars',
url: '/img/tarokka/Stars_06_Evoker.jpeg',
},
{
id: 'Stars_07_Illusionist',
name: 'Illusionist',
card: 'Seven of Stars',
description: 'Lies and deceit; grand conspiracies; secret societies; the presence of a dupe or a saboteur',
aria: 'Stars 07 Illusionist',
back: false,
suit: 'Stars',
url: '/img/tarokka/Stars_07_Illusionist.jpeg',
},
{
id: 'Stars_08_Necromancer',
name: 'Necromancer',
card: 'Eight of Stars',
description: 'Unnatural events and unhealthy obsessions; those who follow a destructive path',
aria: 'Stars 08 Necromancer',
back: false,
suit: 'Stars',
url: '/img/tarokka/Stars_08_Necromancer.jpeg',
},
{
id: 'Stars_09_Conjurer',
name: 'Conjurer',
card: 'Nine of Stars',
description: 'The coming of an unexpected supernatural threat; those who think of themselves as gods',
aria: 'Stars 09 Conjurer',
back: false,
suit: 'Stars',
url: '/img/tarokka/Stars_09_Conjurer.jpeg',
},
{
id: 'Stars_10_Wizard',
name: 'Wizard',
card: 'Master of Stars',
description: 'Mystery and riddles; the unknown; those who crave magical power and great knowledge',
aria: 'Stars 10 Wizard',
back: false,
suit: 'Stars',
url: '/img/tarokka/Stars_10_Wizard.jpeg',
},
{
id: 'Swords_01_Avenger',
name: 'Avenger',
card: 'One of Swords',
description: 'Justice and revenge for great wrongs; those on a quest to rid the world of great evil',
aria: 'Swords 01 Avenger',
back: false,
suit: 'Swords',
url: '/img/tarokka/Swords_01_Avenger.jpeg',
},
{
id: 'Swords_02_Paladin',
name: 'Paladin',
card: 'Two of Swords',
description: 'Just and noble warriors; those who live by a code of honor and integrity',
aria: 'Swords 02 Paladin',
back: false,
suit: 'Swords',
url: '/img/tarokka/Swords_02_Paladin.jpeg',
},
{
id: 'Swords_03_Soldier',
name: 'Soldier',
card: 'Three of Swords',
description: 'War and sacrifice; the stamina to endure great hardship',
aria: 'Swords 03 Soldier',
back: false,
suit: 'Swords',
url: '/img/tarokka/Swords_03_Soldier.jpeg',
},
{
id: 'Swords_04_Mercenary',
name: 'Mercenary',
card: 'Four of Swords',
description: 'Inner strength and fortitude; those who fight for power or wealth',
aria: 'Swords 04 Mercenary',
back: false,
suit: 'Swords',
url: '/img/tarokka/Swords_04_Mercenary.jpeg',
},
{
id: 'Swords_05_Myrmidon',
name: 'Myrmidon',
card: 'Five of Swords',
description: 'Great heroes; a sudden reversal of fate; the triumph of the underdog over a mighty enemy',
aria: 'Swords 05 Myrmidon',
back: false,
suit: 'Swords',
url: '/img/tarokka/Swords_05_Myrmidon.jpeg',
},
{
id: 'Swords_06_Berserker',
name: 'Berserker',
card: 'Six of Swords',
description: 'The brutal and barbaric side of warfare; bloodlust; those with a bestial nature',
aria: 'Swords 06 Berserker',
back: false,
suit: 'Swords',
url: '/img/tarokka/Swords_06_Berserker.jpeg',
},
{
id: 'Swords_07_HoodedOne',
name: 'Hooded One',
card: 'Seven of Swords',
description: 'Bigotry, intolerance, and xenophobia; a mysterious presence or newcomer',
aria: 'Swords 07 Hooded One',
back: false,
suit: 'Swords',
url: '/img/tarokka/Swords_07_HoodedOne.jpeg',
},
{
id: 'Swords_08_Dictator',
name: 'Dictator',
card: 'Eight of Swords',
description: 'All that is wrong with government and leadership; those who rule through fear and violence',
aria: 'Swords 08 Dictator',
back: false,
suit: 'Swords',
url: '/img/tarokka/Swords_08_Dictator.jpeg',
},
{
id: 'Swords_09_Torturer',
name: 'Torturer',
card: 'Nine of Swords',
description: 'The coming of suffering or merciless cruelty; one who is irredeemably evil or sadistic',
aria: 'Swords 09 Torturer',
back: false,
suit: 'Swords',
url: '/img/tarokka/Swords_09_Torturer.jpeg',
},
{
id: 'Swords_10_Warrior',
name: 'Warrior',
card: 'Master of Swords',
description: 'Strength and force personified; violence; those who use force to accomplish their goals',
aria: 'Swords 10 Warrior',
back: false,
suit: 'Swords',
url: '/img/tarokka/Swords_10_Warrior.jpeg',
},
{
id: 'Crowns_Artifact',
name: 'Artifact',
card: 'The Artifact',
description: 'The importance of some physical object that must be obtained, protected, or destroyed at all costs',
aria: 'High Deck Artifact',
back: false,
suit: 'High Deck',
url: '/img/tarokka/Crowns_Artifact.jpeg',
},
{
id: 'Crowns_Beast',
name: 'Beast',
card: 'The Beast',
description: 'Great rage or passion; something bestial or malevolent hiding in plain sight or lurking just below the surface',
aria: 'High Deck Beast',
back: false,
suit: 'High Deck',
url: '/img/tarokka/Crowns_Beast.jpeg',
},
{
id: 'Crowns_BrokenOne',
name: 'Broken One',
card: 'The Broken One',
description: 'Defeat, failure, and despair; the loss of something or someone important, without which one feels incomplete',
aria: 'High Deck Broken One',
back: false,
suit: 'High Deck',
url: '/img/tarokka/Crowns_BrokenOne.jpeg',
},
{
id: 'Crowns_Darklord',
name: 'Darklord',
card: 'The Darklord',
description: 'A single, powerful individual of an evil nature, one whose goals have enormous and far-reaching consequences',
aria: 'High Deck Darklord',
back: false,
suit: 'High Deck',
url: '/img/tarokka/Crowns_Darklord.jpeg',
},
{
id: 'Crowns_Donjon',
name: 'Donjon',
card: 'The Donjon',
description: 'Isolation and imprisonment; being so conservative in thinking as to be a prisoner of one\'s own beliefs',
aria: 'High Deck Donjon',
back: false,
suit: 'High Deck',
url: '/img/tarokka/Crowns_Donjon.jpeg',
},
{
id: 'Crowns_Executioner',
name: 'Executioner',
card: 'The Executioner',
description: 'The imminent death of one rightly or wrongly convicted of a crime; false accusations and unjust prosecution',
aria: 'High Deck Executioner',
back: false,
suit: 'High Deck',
url: '/img/tarokka/Crowns_Executioner.jpeg',
},
{
id: 'Crowns_Ghost',
name: 'Ghost',
card: 'The Ghost',
description: 'The looming past; the return of an old enemy or the discovery of a secret buried long ago',
aria: 'High Deck Ghost',
back: false,
suit: 'High Deck',
url: '/img/tarokka/Crowns_Ghost.jpeg',
},
{
id: 'Crowns_Horseman',
name: 'Horseman',
card: 'The Horseman',
description: 'Death; disaster in the form of the loss of wealth or property, a horrible defeat, or the end of a bloodline',
aria: 'High Deck Horseman',
back: false,
suit: 'High Deck',
url: '/img/tarokka/Crowns_Horseman.jpeg',
},
{
id: 'Crowns_Innoncent',
name: 'Innocent',
card: 'The Innoncent',
description: 'A being of great importance whose life is in danger (who might be helpless or simply unaware of the peril)',
aria: 'High Deck Innocent',
back: false,
suit: 'High Deck',
url: '/img/tarokka/Crowns_Innoncent.jpeg',
},
{
id: 'Crowns_Marionette',
name: 'Marionette',
card: 'The Marionette',
description: 'The presence of a spy or a minion of some greater power; an encounter with a puppet or an underling',
aria: 'High Deck Marionette',
back: false,
suit: 'High Deck',
url: '/img/tarokka/Crowns_Marionette.jpeg',
},
{
id: 'Crowns_Mists',
name: 'Mists',
card: 'The Mists',
description: 'Something unexpected or mysterious that can\'t be avoided; a great quest or journey that will try one\'s spirit',
aria: 'High Deck Mists',
back: false,
suit: 'High Deck',
url: '/img/tarokka/Crowns_Mists.jpeg',
},
{
id: 'Crowns_Raven',
name: 'Raven',
card: 'The Raven',
description: 'A hidden source of information; a fortunate turn of events; a secret potential for good',
aria: 'High Deck Raven',
back: false,
suit: 'High Deck',
url: '/img/tarokka/Crowns_Raven.jpeg',
},
{
id: 'Crowns_Seer',
name: 'Seer',
card: 'The Seer',
description: 'Inspiration and keen intellect; a future event, the outcome of which will hinge on a clever mind',
aria: 'High Deck Seer',
back: false,
suit: 'High Deck',
url: '/img/tarokka/Crowns_Seer.jpeg',
},
{
id: 'Crowns_Tempter',
name: 'Tempter',
card: 'The Tempter',
description: 'One who has been compromised or led astray by temptation or foolishness; one who tempts others for evil ends',
aria: 'High Deck Tempter',
back: false,
suit: 'High Deck',
url: '/img/tarokka/Crowns_Tempter.png',
}
];
export default tarokkaCards;

View File

@@ -1,8 +1,8 @@
import Cards from './Cards' import Deck from './TarokkaDeck'
import { GameState, GameUpdate } from '../types' import { GameState, GameUpdate } from '../types'
const deck = new Cards(); const deck = new Deck();
export default class GameStore { export default class GameStore {
private games: Map<string, GameState>; private games: Map<string, GameState>;
@@ -44,11 +44,11 @@ export default class GameStore {
return game; return game;
} }
flipCard(gameID: string, cardID: string): GameUpdate { flipCard(gameID: string, cardIndex: number): GameUpdate {
const game = this.getGame(gameID); const game = this.getGame(gameID);
const card = game.cards.find(c => c.id === cardID); const card = game.cards[cardIndex];
if (!card) throw new Error(`Card ${cardID} not found`); if (!card) throw new Error(`Card ${cardIndex} not found`);
card.flipped = !card.flipped; card.flipped = !card.flipped;
game.lastUpdated = Date.now(); game.lastUpdated = Date.now();
@@ -66,7 +66,7 @@ export default class GameStore {
gameUpdate(game: GameState): GameUpdate { gameUpdate(game: GameState): GameUpdate {
const { id, cards } = game; const { id, cards } = game;
return { id, cards }; return { id, cards: cards.map(card => card.flipped ? card : deck.getBack()) };
} }
deleteGame(gameID: string): void { deleteGame(gameID: string): void {

View File

@@ -1,6 +1,6 @@
import getRandomItems from '../tools/getRandomItems'; import getRandomItems from '../tools/getRandomItems';
import cards from '../const/cards'; import cards from '../constants/standardCards';
import type { CardImage } from '@/types'; import type { StandardCard } from '../types';
export interface Options { export interface Options {
back: number; back: number;
@@ -20,10 +20,9 @@ const DEFAULT_OPTIONS = {
export default class Cards { export default class Cards {
private options: Options; private options: Options;
private deck: CardImage[] = []; private deck: StandardCard[] = [];
private backs: CardImage[] = []; private backs: StandardCard[] = [];
private jokers: CardImage[] = []; private jokers: StandardCard[] = [];
constructor(options: OptionProps = {}) { constructor(options: OptionProps = {}) {
this.options = { ...DEFAULT_OPTIONS, ...options }; this.options = { ...DEFAULT_OPTIONS, ...options };
@@ -33,16 +32,16 @@ export default class Cards {
this.jokers = cards.filter(card => card.joker); this.jokers = cards.filter(card => card.joker);
} }
select(count: number): CardImage[] { select(count: number): StandardCard[] {
return getRandomItems(this.deck, count); return getRandomItems(this.deck, count);
} }
getBack(style: number): CardImage { getBack(style: number): StandardCard {
style = style || this.options.back; style = style || this.options.back;
return this.backs.find(card => card.id.startsWith(String(style))) || this.backs[0]; return this.backs.find(card => card.id.startsWith(String(style))) || this.backs[0];
} }
getJokers(): CardImage[] { getJokers(): StandardCard[] {
return this.jokers; return this.jokers;
} }
} }

21
lib/TarokkaDeck.ts Normal file
View File

@@ -0,0 +1,21 @@
import getRandomItems from '../tools/getRandomItems';
import cards from '../constants/tarokkaCards';
import type { TarokkaCard } from '../types';
export default class TarokkaDeck {
private deck: TarokkaCard[] = [];
private backs: TarokkaCard[] = [];
constructor() {
this.deck = cards.filter(card => !card.back);
this.backs = cards.filter(card => card.back);
}
select(count: number): TarokkaCard[] {
return getRandomItems(this.deck, count);
}
getBack(): TarokkaCard {
return this.backs[0];
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
public/img/Tarokka/Back.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

BIN
public/img/table1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

BIN
public/img/table2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

View File

@@ -32,10 +32,10 @@ app.prepare().then(() => {
socket.emit('init', gameUpdate); socket.emit('init', gameUpdate);
}) })
socket.on('flip-card', ({ gameID, cardID }: ClientUpdate) => { socket.on('flip-card', ({ gameID, cardIndex }: ClientUpdate) => {
console.log('Card flipped:', { gameID, cardID }); console.log('Card flipped:', { gameID, cardIndex });
const gameUpdate = gameStore.flipCard(gameID, cardID); const gameUpdate = gameStore.flipCard(gameID, cardIndex);
io.to(gameID).emit('card-flipped', gameUpdate); io.to(gameID).emit('card-flipped', gameUpdate);
}); });

View File

@@ -1,5 +1,6 @@
export interface CardImage { export interface StandardCard {
id: string; id: string;
aria: string;
back: boolean; back: boolean;
face: boolean; face: boolean;
joker: boolean; joker: boolean;
@@ -7,23 +8,38 @@ export interface CardImage {
url: string; url: string;
} }
export interface GameCard extends CardImage { export interface StandardGameCard extends StandardCard {
flipped: boolean;
}
export interface TarokkaCard {
id: string;
name: string;
card: string;
description: string;
aria: string;
back: boolean;
suit: 'Coins' | 'Glyphs' | 'High Deck' | 'Stars' | 'Swords' | null;
url: string;
}
export interface TarokkaGameCard extends TarokkaCard {
flipped: boolean; flipped: boolean;
} }
export interface GameState { export interface GameState {
id: string; id: string;
players: Set<string>; players: Set<string>;
cards: GameCard[]; cards: StandardGameCard[] | TarokkaGameCard[];
lastUpdated: number; lastUpdated: number;
} }
export interface GameUpdate { export interface GameUpdate {
id: string; id: string;
cards: GameCard[]; cards: StandardGameCard[] | TarokkaGameCard[];
} }
export interface ClientUpdate { export interface ClientUpdate {
gameID: string; gameID: string;
cardID: string; cardIndex: number;
} }