slanted-gamedev-toolz
Version:
A slanted mix of tools for your brilliant ideas in game design.
219 lines (218 loc) • 10.5 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useCallback, useEffect, useState } from "react";
import { getModdedDeck, getRandomMods, levelCards, } from "../../cardDecks/catsDeck";
import { CardHand } from "../CardHand/CardHand";
import { DiscardBtn } from "./DiscardBtn";
import { GameHeader } from "./GameHeader";
import { HandScore } from "./HandScore";
import { MatchScore } from "./MatchScore";
import { OutComes } from "./OutComes";
import { PlayHandBtn } from "./PlayHandBtn";
import { ShuffleDealBtn } from "./ShuffleDealBtn";
import { useCatDeckHandScore } from "./hooks/useCatDeckHandScore";
import { useSpeech } from "./hooks/useSpeech";
import { bgGradient } from "./style/catDeskSx";
import "./style/CatDeck.css";
import "@fontsource/nova-cut";
import "@fontsource-variable/alegreya";
import { BtnWrapRow } from "./BtnWrapRow";
import { HandFooter } from "./HandFooter";
import { IntroScreen } from "./IntroScreen";
import { useCardOverlap } from "./hooks/useCardOverlap";
import useCatInterval from "./hooks/useCatInterval";
import { usePlayCatMusicFile } from "./hooks/usePlayCatMusicFile";
export const CatDeckDealer = ({ deck, handSize, }) => {
const [tick, setTick] = useState(0);
const [hasInteracted, setHasInteracted] = useState(false);
useCatInterval(() => {
setTick((t) => t + 1);
}, 75);
usePlayCatMusicFile({
hasInteracted,
});
// const [gamepads, setGamepads] = useState({});
// useGamepadCatDeck((gamepads) => setGamepads(gamepads));
// const isAPressed = gamepads[0]?.buttons[0].pressed;
// if (isAPressed) {
// console.log("isAPressed");
// }
const { speak, cancelSpeaking } = useSpeech({ isMuteSpeech: false });
const level1Target = 100;
// LEVEL
const [runLevel, setRunLevel] = useState(1);
const [levelTarget, setLevelTarget] = useState(level1Target);
const [levelScore, setLevelScore] = useState(0);
const [isLevelBeaten, setIsLevelBeaten] = useState(false);
const [discardsRemainingMax, setDiscardsRemainingMax] = useState(3);
const [discardsRemaining, setDiscardsRemaining] = useState(discardsRemainingMax); //prettier-ignore
const [maxHands, setMaxHands] = useState(3);
const [handsRemaining, setHandsRemaining] = useState(maxHands);
// Deck
const [modCards, setModCards] = useState([]);
const [remainingDeck, setRemainingDeck] = useState(getModdedDeck({ deck, modCards })); //prettier-ignore
// HAND
const [hand, setHand] = useState([]);
const [selectedHand, setSelectedHand] = useState([]);
const [selectedHandIndexes, setSelectedHandIndexes] = useState([]);
const [lastHand, setLastHand] = useState([]);
const [lastHandScore, setLastHandScore] = useState(0);
const [lastOutcomes, setLastOutcomes] = useState([
levelCards[0],
]);
const hasSelectedCards = selectedHandIndexes.length > 0;
const { handScore, outcomes, multiplier, baseScore, clearOutcomes } = useCatDeckHandScore({
hand: selectedHand,
modCards,
lastHand,
lastOutcomes,
}); //prettier-ignore
const clickDiscard = useCallback(() => {
if (!hasSelectedCards)
return;
// reduce remaining discard plays
setDiscardsRemaining((p) => {
const def = 3;
if (p === 0)
return def;
return p - 1;
});
// discard card in hand
setHand((prevHand) => {
return prevHand.filter((_, index) => !selectedHandIndexes.includes(index));
});
setSelectedHandIndexes([]);
setSelectedHand([]);
// draw new cards
const discardCount = selectedHandIndexes.length;
const shuffledDeck = [...remainingDeck].sort(() => Math.random() - 0.5);
const draw = shuffledDeck.slice(0, discardCount);
const updatedRemainingDeck = [...shuffledDeck.slice(discardCount)];
setRemainingDeck(updatedRemainingDeck);
setHand((prevHand) => {
return [...prevHand, ...draw];
});
}, [hasSelectedCards, remainingDeck, selectedHandIndexes]);
const clickPlayHand = useCallback(() => {
// reduce remaining plays
setHandsRemaining((p) => {
const def = 3;
if (p === 0)
return def;
return p - 1;
});
setLastHand(selectedHand);
setLastHandScore(handScore);
setLastOutcomes(outcomes);
setHand([]);
setSelectedHand([]);
setSelectedHandIndexes([]);
setLevelScore((p) => {
const newMatchScore = p + handScore;
if (newMatchScore >= levelTarget) {
setIsLevelBeaten(true);
}
return newMatchScore;
});
const readTextString = outcomes.map((o) => `${o.headName}`).join(" ");
cancelSpeaking();
speak(readTextString);
}, [cancelSpeaking, handScore, levelTarget, outcomes, selectedHand, speak]);
const shuffleDeck = useCallback(() => {
setRemainingDeck(getModdedDeck({ deck, modCards }));
}, [deck, modCards]);
const restartGame = useCallback(() => {
console.log("restartGame");
shuffleDeck();
setIsLevelBeaten(false);
setHandsRemaining(maxHands);
setLevelTarget(level1Target);
setLevelScore(0);
setRunLevel(1);
setLastHand([]);
setLastOutcomes([]);
clearOutcomes();
setLastHandScore(0);
setModCards([]);
setSelectedHand([]);
setSelectedHandIndexes([]);
setDiscardsRemaining(discardsRemainingMax);
}, [clearOutcomes, discardsRemainingMax, maxHands, shuffleDeck]);
const isNeedShuffle = remainingDeck.length < handSize;
const isAllowDealing = isNeedShuffle || hand.length === 0;
const nextHand = useCallback(() => {
if (!isAllowDealing)
return;
setHasInteracted(true);
clearOutcomes();
setLastOutcomes([]);
setLastHand([]);
setLastHandScore(0);
setSelectedHand([]);
setSelectedHandIndexes([]);
const shuffledDeck = [...remainingDeck].sort(() => Math.random() - 0.5);
const newHand = shuffledDeck.slice(0, handSize);
const updatedRemainingDeck = [...shuffledDeck.slice(handSize)];
setHand([...newHand]);
setRemainingDeck(updatedRemainingDeck);
}, [isAllowDealing, clearOutcomes, remainingDeck, handSize]);
const nextLevel = useCallback(() => {
setModCards(getRandomMods(runLevel));
setIsLevelBeaten(false);
setHandsRemaining(maxHands);
setLevelTarget((p) => p * 2);
setRunLevel((p) => p + 1);
setLevelScore(0);
setDiscardsRemaining(discardsRemainingMax);
nextHand();
}, [nextHand, discardsRemainingMax, maxHands, runLevel]);
const isHandDealt = hand.length > 1;
const showTurnBtns = isHandDealt && !isNeedShuffle;
const isOutOfHands = handsRemaining === 0;
const showNextLevelBtn = isOutOfHands || isLevelBeaten;
const isGameOver = isOutOfHands && !isLevelBeaten;
const modMyCards = useCallback(() => {
setHand((p) => getModdedDeck({ deck: p, modCards }));
setRemainingDeck((p) => getModdedDeck({ deck: p, modCards }));
}, []);
useEffect(() => {
if (runLevel)
speak(`Level ${runLevel}`);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [runLevel]);
useEffect(() => {
if (levelTarget)
speak(`Target: ${levelTarget} cats`);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [levelTarget]);
useEffect(() => {
if (lastHandScore)
speak(`${lastHandScore} cats join`);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [lastHandScore]);
useEffect(() => {
if (isLevelBeaten) {
speak("Level Complete!");
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isLevelBeaten]);
useEffect(() => {
if (isGameOver)
speak("Game Over");
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isGameOver]);
const isHandInPlay = hand.length > 0;
const { overlap } = useCardOverlap();
if (!hasInteracted) {
return (_jsx(IntroScreen, { setHasInteracted: setHasInteracted, overlap: overlap }));
}
return (_jsxs("div", { style: deckStyle, children: [_jsx(GameHeader, { runLevel: runLevel, isLevelBeaten: isLevelBeaten, isGameOver: isGameOver }), _jsx(MatchScore, { score: levelScore, target: levelTarget }), _jsx(BtnWrapRow, { children: _jsx(ShuffleDealBtn, { levelScore: levelScore, isHandDealt: isHandDealt, showNextLevelBtn: showNextLevelBtn, isGameOver: isGameOver, isAllowDealing: isAllowDealing, shuffleDeck: shuffleDeck, remainingDeck: remainingDeck, nextLevel: nextLevel, isLevelBeaten: isLevelBeaten, nextHand: nextHand, handsRemaining: handsRemaining, isOutOfHands: isOutOfHands, restartGame: restartGame }) }), _jsxs(CardHand, { cards: hand, overlap: overlap, chaos: 2, selectedLift: -20, isUnSelectable: false, selectedHandIndexes: selectedHandIndexes, setSelectedHandIndexes: setSelectedHandIndexes, setSelectedHand: setSelectedHand, children: [_jsx(HandFooter, { hand: hand }), _jsxs(BtnWrapRow, { children: [_jsx(DiscardBtn, { clickDiscard: clickDiscard, discardsRemaining: discardsRemaining, hasSelectedCards: hasSelectedCards, showTurnBtns: showTurnBtns }), _jsx(PlayHandBtn, { clickPlayHand: clickPlayHand, selectedHand: selectedHand, handsRemaining: handsRemaining, showTurnBtns: showTurnBtns })] }), _jsx(HandScore, { score: handScore, baseScore: baseScore, multiplier: multiplier }), _jsx(OutComes, { levelTarget: levelTarget, isLevelBeaten: isLevelBeaten, outcomes: outcomes, levelScore: levelScore, overlap: overlap, lastHand: lastHand, lastOutcomes: lastOutcomes, isHandInPlay: isHandInPlay, lastHandScore: lastHandScore })] }), _jsx(_Fragment, { children: modCards.length ? (_jsxs(_Fragment, { children: [_jsxs("h1", { style: { textAlign: "center" }, children: ["Mods: ", modCards.length] }), _jsx(CardHand, { cards: modCards, overlap: 20 })] })) : null })] }));
};
const deckStyle = {
backgroundImage: bgGradient,
paddingTop: "15px",
borderRadius: "2px",
minHeight: "100vh",
body: {
fontFamily: "'Nova Cut', system-ui",
},
};