From c4bbadbbf53ec0a15792eeea0a05d5be12332772 Mon Sep 17 00:00:00 2001 From: Isaac Date: Sat, 14 Sep 2024 20:49:49 -0700 Subject: [PATCH] Joker activation revamp, cleanup --- src/App.tsx | 28 +- src/Constants.ts | 31 +- src/GameState.ts | 318 ++++++++++++------ src/Utilities.ts | 4 +- src/assets/jokers/Common/Mail-In_Rebate.png | Bin 0 -> 3481 bytes src/assets/jokers/Common/Photograph.png | Bin 0 -> 9695 bytes src/assets/jokers/Common/Reserved_Parking.png | Bin 0 -> 2006 bytes src/assets/jokers/Rare/Obelisk.png | Bin 0 -> 7441 bytes src/assets/jokers/Uncommon/Gift_Card.png | Bin 0 -> 2609 bytes src/assets/jokers/Uncommon/Midas_Mask.png | Bin 0 -> 6078 bytes src/assets/jokers/Uncommon/Rocket.png | Bin 0 -> 5562 bytes src/assets/jokers/Uncommon/Turtle_Bean.png | Bin 0 -> 4652 bytes src/components/Blind.tsx | 26 +- src/components/Hand.tsx | 11 +- src/components/Joker.tsx | 3 + src/components/JokerInfo.ts | 294 +++++++++++----- src/components/MainMenu.css | 5 + src/components/MainMenu.tsx | 6 +- src/components/Options.tsx | 4 +- src/components/PlayMenu.tsx | 2 +- src/components/Shop.tsx | 2 +- 21 files changed, 511 insertions(+), 223 deletions(-) create mode 100644 src/assets/jokers/Common/Mail-In_Rebate.png create mode 100644 src/assets/jokers/Common/Photograph.png create mode 100644 src/assets/jokers/Common/Reserved_Parking.png create mode 100644 src/assets/jokers/Rare/Obelisk.png create mode 100644 src/assets/jokers/Uncommon/Gift_Card.png create mode 100644 src/assets/jokers/Uncommon/Midas_Mask.png create mode 100644 src/assets/jokers/Uncommon/Rocket.png create mode 100644 src/assets/jokers/Uncommon/Turtle_Bean.png diff --git a/src/App.tsx b/src/App.tsx index 0c8e7e8..e80c59b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -11,7 +11,7 @@ import { InfoPanel } from './components/InfoPanel' import { Joker } from './components/Joker' import { Round } from './components/Round' import { Shop } from './components/Shop' -import { Blinds } from './Constants' +import { Blinds, DeckType } from './Constants' import { gameReducer, GameStateContext, initialGameState } from './GameState' import { cardSnap } from './Utilities' import { MainMenu } from './components/MainMenu' @@ -45,7 +45,13 @@ export default function App() { const currBlindType = game.blind.curr === 'small' ? Blinds[0] : game.blind.curr === 'big' ? Blinds[1] : game.blind.boss - const reward = currBlindType.reward + game.stats.hands + Math.min(Math.floor(game.stats.money / 5), 5) + let reward = currBlindType.reward + if(game.stats.deck === DeckType.Green) { + reward += 2 * game.stats.hands + game.stats.discards + } else { + reward += game.stats.hands + Math.min(Math.floor(game.stats.money / 5), 5) + } + return ( @@ -111,14 +117,28 @@ export default function App() { }}>{`Cash Out: $${reward}`}
{'. '.repeat(49)}
- {game.stats.hands > 0 && + {game.stats.deck !== DeckType.Green && game.stats.hands > 0 &&
{game.stats.hands}
{'Remaining Hands \[$1 each\]'}
{'$'.repeat(game.stats.hands)}
} - {game.stats.money > 4 && + {game.stats.deck === DeckType.Green && game.stats.hands > 0 && +
+
{game.stats.hands}
+
{'Remaining Hands \[$2 each\]'}
+
{'$'.repeat(2 * game.stats.hands)}
+
+ } + {game.stats.deck === DeckType.Green && game.stats.discards > 0 && +
+
{game.stats.discards}
+
{'Remaining Discards \[$1 each\]'}
+
{'$'.repeat(game.stats.discards)}
+
+ } + {game.stats.deck !== DeckType.Green && game.stats.money > 4 &&
{Math.min(Math.floor(game.stats.money / 5), 5)}
{'1 interest per $5 \[5 max\]'}
diff --git a/src/Constants.ts b/src/Constants.ts index 993b068..2da613e 100644 --- a/src/Constants.ts +++ b/src/Constants.ts @@ -1,22 +1,39 @@ -export enum DeckType { Abandoned, Anaglyph, Black, Blue, Challenge, Checkered, Erratic, Ghost, Green, Magic, Nebula, Painted, Plasma, Red, Yellow, Zodiac } +export enum DeckType { + Abandoned, + // Anaglyph, + Black, + Blue, + // Challenge, + Checkered, + Erratic, + Ghost, + Green, + // Magic, + // Nebula, + Painted, + // Plasma, + Red, + Yellow, + // Zodiac +} export const deckInfo: {[D in keyof typeof DeckType]: string} = { Abandoned: 'Start run with\n no/ {orange}Face Cards\n in your deck', - Anaglyph: '', + // Anaglyph: '', Black: '{orange}+1/ Joker slot\n {blue}-1/ hand\n every round', Blue: '{blue}+1/ hand\n every round', - Challenge: '', + // Challenge: '', Checkered: 'Start run with\n {orange}26/ {dark-purple}Spades/ and\n {orange}26/ {red}Hearts/ in deck', Erratic: 'All Ranks and\n Suits in deck\n are randomized', Ghost: '{indigo}Spectral/ cards may\n appear in the shop,\n start with a/ {indigo}Hex/ card', Green: 'At end of each Round:\n {yellow}$2/ {small black}per remaining/ {blue}Hand\n {yellow}$1/ {small black}per remaining/ {red}Discard\n Earn no/ {orange}Interest', - Magic: 'Start run with the\n {purple}Crystal Ball/ voucher\n and/ {orange}2/ copies\n of/ {purple}The Fool', - Nebula: 'Start run with the\n {aqua}Telescope/ voucher\n {red}-1/ consumable slot', + // Magic: 'Start run with the\n {purple}Crystal Ball/ voucher\n and/ {orange}2/ copies\n of/ {purple}The Fool', + // Nebula: 'Start run with the\n {aqua}Telescope/ voucher\n {red}-1/ consumable slot', Painted: '{orange}+2/ Hand Size,\n {orange}-1/ Joker Slot', - Plasma: '', + // Plasma: '', Red: '{red}+1/ discard\n every round', Yellow: 'Start with\n extra/ {yellow}$10', - Zodiac: 'Start run with\n {purple}Tarot Merchant/,\n {aqua}Planet Merchant/,\n and {orange}Overstock' + // Zodiac: 'Start run with\n {purple}Tarot Merchant/,\n {aqua}Planet Merchant/,\n and {orange}Overstock' } export enum Suit { Spades, Hearts, Clubs, Diamonds } diff --git a/src/GameState.ts b/src/GameState.ts index d2b1a94..658ec0c 100644 --- a/src/GameState.ts +++ b/src/GameState.ts @@ -2,7 +2,7 @@ import { createContext, Dispatch } from "react" import { BlindType, ConsumableInstance, Consumables, ConsumableType, DeckType, Edition, Enhancement, handLevels, HandType, handUpgrade, Rank, rankChips, Seal, Suit } from "./Constants" import { ante_base, AnteBlinds, bestHand, boss_roll, cardSnap, debuffCards, getNextBlind, newOffers, shuffle } from "./Utilities" import { CardInfo } from "./components/CardInfo" -import { Activation, JokerInstance, Jokers, JokerType } from "./components/JokerInfo" +import { Activation, JokerInstance, JokerType } from "./components/JokerInfo" import Rand from "rand-seed" export let Random: Rand = new Rand() @@ -13,12 +13,20 @@ export const levelHand = ({ hand, n = 1 }: {hand: keyof typeof handLevels, n?: n handLevels[hand].mult += handUpgrade[hand].mult * n } +export const addCard = ({ game, card, loc }: {game: GameState, card: CardInfo, loc: 'hand' | 'deck'}) => { + game.cards[loc].push({...card, + id: game.cards.nextId, + selected: false, + submitted: false, + scored: false + }) + game.cards.nextId++ +} + type GameStates = 'main-menu' | 'blind-select' | 'scoring' | 'post-scoring' | 'shop' export type GameState = { state: GameStates - seed: string - seeded: boolean stats: { handSize: number @@ -31,6 +39,8 @@ export type GameState = { consumableSize: number jokerSize: number deck: DeckType + seed: string + seeded: boolean } shop: { @@ -102,7 +112,8 @@ export type GameAction = { state?: GameStates - stat?: keyof typeof initialGameState['stats'] + stat?: 'handSize' | 'hands' | 'discards' | 'money' | 'ante' | 'round' | 'score' | 'consumableSize' | 'jokerSize' + previous?: 'played' | 'discarded' // To know during a draw which came previously amount?: number @@ -116,20 +127,20 @@ export type GameAction = { export const initialGameState: GameState = { state: 'main-menu' as GameStates, - seed: '', - seeded: false, - + stats: { handSize: 8, hands: 4, - discards: 4, - money: 9999999, + discards: 3, + money: 0, ante: 1, round: 0, score: 0, consumableSize: 2, jokerSize: 5, - deck: DeckType.Red + deck: DeckType.Red, + seed: '', + seeded: false }, shop: { @@ -187,56 +198,109 @@ export const gameReducer = (state: GameState, action: GameAction): GameState => (a.suit !== b.suit ? a.suit - b.suit : b.rank - a.rank) ) let suits = Object.keys(Suit).filter(k => isNaN(Number(k))).map(s => s as keyof typeof Suit) - let ranks = Object.keys(Rank).filter(r => isNaN(Number(r))).map(r => r as keyof typeof Rank) + let ranks = Object.keys(Rank).filter(r => isNaN(Number(r))).map(r => r as keyof typeof Rank) let next = state, name = state.blind.boss.name switch(action.type) { case 'init': + switch(action.payload?.deck!) { + case DeckType.Red: + initialGameState.stats.discards++ + break + case DeckType.Blue: + initialGameState.stats.hands++ + break + case DeckType.Yellow: + initialGameState.stats.money += 10 + break + case DeckType.Black: + initialGameState.stats.jokerSize++ + initialGameState.stats.hands-- + break + case DeckType.Ghost: + next.shop.weights.Spectral = 4 + next.cards.consumables = [{ + id: 0, + consumable: Consumables[24] + }] + break + case DeckType.Painted: + initialGameState.stats.handSize += 2 + initialGameState.stats.jokerSize-- + break + } + next = initialGameState let arr: CardInfo[] = [] switch(action.payload?.deck!) { case DeckType.Erratic: for(let i = 1; i <= 52; i++) { let rank = Rank[ranks[Math.floor(Random.next()*ranks.length)]] - arr.push( - { - id: i, - suit: Suit[suits[Math.floor(Random.next()*suits.length)]], - rank: rank, - chips: rankChips[rank], - deck: DeckType.Erratic - } - ) + arr.push({ + id: i, + suit: Suit[suits[Math.floor(Random.next()*suits.length)]], + rank: rank, + chips: rankChips[Rank[rank] as keyof typeof rankChips], + deck: DeckType.Erratic + }) } - break - default: - suits.forEach(s => { ranks.forEach(r => { - arr.push( - { + next.cards.nextId = 53 + break + case DeckType.Abandoned: + suits.forEach(s => {ranks.forEach(r => { + if(!["Jack", "Queen", "King"].includes(r)) { + arr.push({ id: arr.length + 1, suit: Suit[s], rank: Rank[r], chips: rankChips[r], deck: action.payload?.deck! - } - ) + }) + } })}) + next.cards.nextId = 41 + break + case DeckType.Checkered: + suits.filter(s => ["Spades", "Hearts"].includes(s)).forEach(s => { + for(let i = 0; i < 2; i++) { + ranks.forEach(r => { + arr.push({ + id: arr.length + 1, + suit: Suit[s], + rank: Rank[r], + chips: rankChips[r], + deck: action.payload?.deck! + }) + }) + } + }) + next.cards.nextId = 53 + break + default: + suits.forEach(s => {ranks.forEach(r => { + arr.push({ + id: arr.length + 1, + suit: Suit[s], + rank: Rank[r], + chips: rankChips[r], + deck: action.payload?.deck! + }) + })}) + next.cards.nextId = 53 } - next = initialGameState next = {...next, - seed: action.payload?.seed ?? (Math.random() + 1).toString(36).toUpperCase().slice(2), - seeded: action.payload?.seed !== undefined, stats: {...state.stats, - deck: action.payload?.deck! + deck: action.payload?.deck!, + seed: action.payload?.seed ?? (Math.random() + 1).toString(36).toUpperCase().slice(2), + seeded: action.payload?.seed !== undefined }, blind: {...state.blind, boss: boss_roll(state.stats.ante), base: ante_base(state.stats.ante) }, cards: {...state.cards, - nextId: 53, deck: arr } } - Random = new Rand(next.seed) + Random = new Rand(next.stats.seed) break case 'state': next = {...next, @@ -244,81 +308,27 @@ export const gameReducer = (state: GameState, action: GameAction): GameState => } switch(action.payload?.state) { case 'scoring': - next = {...next, - stats: {...state.stats, - round: state.stats.round + 1 - }, - cards: {...state.cards, - deck: shuffle(state.cards.deck) - } - } + next.stats.round++ + next.cards.deck = shuffle(state.cards.deck) + if(state.blind.curr === 'boss') { debuffCards(state.blind.boss, next.cards.deck, state.cards.played) - if(name === 'The Needle') { - next.stats.hands = 1 - } else if(name === 'The Water') { - next.stats.discards = 0 - } else if(name === 'Crimson Heart') { - next.jokers[Math.floor(Random.next() * next.jokers.length)].debuffed = true - } else if(name === 'Amber Acorn') { - next.jokers.forEach(j => j.flipped = true) - next = {...next, - jokers: shuffle(next.jokers) - } - } - } - state.jokers.filter(j => j.joker.activation.includes(Activation.OnBlind)).forEach(j => { - switch(j.joker.name) { - case 'Marble Joker': - next = {...next, - cards: {...next.cards, - nextId: next.cards.nextId + 1, - deck: [...next.cards.deck, { - id: next.cards.nextId, - suit: Suit[suits[Math.floor(Random.next()*suits.length)]], - rank: Rank[ranks[Math.floor(Random.next()*ranks.length)]], - chips: 50, - enhancement: Enhancement.Stone, - deck: DeckType.Red - }] - } - } - break - case 'Burglar': - next.stats.hands += 3 - next.stats.discards = 0 + switch(name) { + case 'The Needle': next.stats.hands = 1; break + case 'The Water': next.stats.discards; break + case 'The Manacle': next.stats.handSize--; break + case 'Crimson Heart': + next.jokers[Math.floor(Random.next() * next.jokers.length)].debuffed = true break - case 'Madness': - if(state.blind.curr !== 'boss') { - j.joker.counter! += 0.5 - let validJokers = state.jokers.filter(joker => joker !== j) - if(validJokers.length > 0) { - let target = validJokers[Math.floor(Random.next() * validJokers.length)].id - next = {...next, - jokers: next.jokers.filter(j => j.id !== target) - } - } - } + case 'Amber Acorn': + next.jokers.forEach(j => j.flipped = true) + next.jokers = shuffle(next.jokers) break - case 'Riff-Raff': - if(state.jokers.length < state.stats.jokerSize) { - let validJokers = Jokers.filter(j => state.jokers.every(joker => joker.joker.name === j.name)) - let joker: JokerType - let nToAdd = Math.min(2, state.stats.jokerSize - state.jokers.length) - for(let i = 0; i < nToAdd; i++) { - if(validJokers.length === 0) { validJokers.push(Jokers[0]) } - joker = validJokers[Math.floor(Random.next() * validJokers.length)] - next = {...next, - jokers: [...next.jokers, { - id: next.cards.nextId + i, - joker: joker - }] - } - validJokers.filter(j => j.name !== joker.name) - } - next.cards.nextId + nToAdd - } } + } + + state.jokers.filter(j => j.joker.activation.includes(Activation.OnBlind) && !j.debuffed).forEach(j => { + next = j.joker.activate(next, j, Activation.OnBlind) }) break case 'post-scoring': @@ -328,7 +338,46 @@ export const gameReducer = (state: GameState, action: GameAction): GameState => c.debuffed = false } ) + + state.cards.hand.filter(c => !c.selected && !c.submitted).forEach(c => { + if(!c.debuffed) { + let will_trigger = c.enhancement === Enhancement?.Gold + state.jokers.filter(j => j.joker.activation.includes(Activation.OnHeld) && !j.debuffed).forEach(j => { + switch(j.joker.name) { + } + }) + + if(will_trigger) { + const cardName = `(Held in hand) ${c.edition ? Edition[c.edition] + ' ' : ''}${c.enhancement ? Enhancement[c.enhancement] + ' ' : ''}${c.seal ? Seal[c.seal] + ' Seal ': ''}${c.enhancement === Enhancement?.Stone ? 'Card' : Rank[c.rank]} of ${Suit[c.suit]}` + next.scoreLog.push({name: cardName}) + + const mime = state.jokers.find(j => j.joker.name === 'Mime') !== undefined + + const heldInHand = () => { + if(c.enhancement === Enhancement?.Gold) { + next.stats.money += 3 + next.scoreLog.push({name: 'Gold Card', notes: '+$3'}) + next.moneyTotalLog += 3 + } + } + + heldInHand() + if(c.seal === Seal?.Red) { + next.scoreLog.push({name: 'Red Seal', notes: 'Retrigger'}) + heldInHand() + } + if(mime) { + state.jokers.filter(j => j.joker.name === 'Mime').forEach(() => { + next.scoreLog.push({name: 'Mime', notes: 'Retrigger'}) + heldInHand() + }) + } + } + } + }) + state.jokers.filter(j => j.joker.activation.includes(Activation.EndOfRound)).forEach(j => { + next = j.joker.activate(next, j, Activation.EndOfRound) switch(j.joker.name) { case 'Egg': j.joker.counter! += 3 @@ -337,6 +386,15 @@ export const gameReducer = (state: GameState, action: GameAction): GameState => // TODO: add to post log next.stats.money += deck.reduce((nines, c) => nines += (c.rank === Rank.Nine ? 1 : 0), 0) break + case 'Rocket': + if(state.blind.curr === 'boss') { + j.joker.counter! += 2 + } + next.stats.money += j.joker.counter! + break + case 'Mail-In Rebate': + j.joker.counter = Math.floor(Random.next() * 13) + break } }) next.jokers.forEach(j => {j.debuffed = false; j.flipped = false}) @@ -523,7 +581,10 @@ export const gameReducer = (state: GameState, action: GameAction): GameState => break case 'Ice Cream': j.joker.counter! = Math.max(0, j.joker.counter! - 5) - break + break + case 'DNA': + next = j.joker.activate(next, j, Activation.OnPlayed, chips, mult) + break case 'Sixth Sense': if(state.cards.firstPlay && selected.length === 1 && selected[0].rank === Rank.Six && state.cards.consumables.length < state.stats.consumableSize) { toRemove.push(selected[0]) @@ -588,6 +649,17 @@ export const gameReducer = (state: GameState, action: GameAction): GameState => nextId: next.cards.nextId + 1 }} } + break + case 'Obelisk': + const mostPlayed = Object.entries(handLevels).reduce((most, hand) => ( + most = (most[1].played < hand[1].played || most[1].chips * most[1].mult < hand[1].chips * hand[1].mult) ? hand : most + ), Object.entries(handLevels)[12]) + if(hand === mostPlayed[0]) { + j.joker.counter! = 1 + } else { + j.joker.counter! += 0.2 + } + break } if(baseball && j.joker.rarity === 'Uncommon') { mult *= 1.5 @@ -753,10 +825,22 @@ export const gameReducer = (state: GameState, action: GameAction): GameState => break case 'Vampire': if(c.enhancement) { - j.joker.counter! += 0.1 + j.joker.counter! = (((j.joker.counter! * 10) + 1) / 10) c.enhancement = undefined } break + case 'Midas Mask': + if([Rank.King, Rank.Queen, Rank.Jack].includes(c.rank)) { + c.enhancement = Enhancement.Gold + } + break + case 'Photograph': + if([Rank.King, Rank.Queen, Rank.Jack].includes(c.rank) && j.joker.counter! > 0) { + mult *= 2 + next.scoreLog.push({name: 'Photograph', mult: 2, mult_type: 'x'}) + j.joker.counter!-- + } + break case 'Triboulet': if([Rank.King, Rank.Queen].includes(c.rank)) { mult *= 2 @@ -1034,6 +1118,12 @@ export const gameReducer = (state: GameState, action: GameAction): GameState => next.scoreLog.push({name: 'Vampire', mult: j.joker.counter!, mult_type: 'x'}) } break + case 'Obelisk': + if(j.joker.counter! > 1) { + mult *= j.joker.counter! + next.scoreLog.push({name: 'Obelisk', mult: j.joker.counter!, mult_type: 'x'}) + } + break } if(baseball && j.joker.rarity === 'Uncommon') { mult *= 1.5 @@ -1052,7 +1142,16 @@ export const gameReducer = (state: GameState, action: GameAction): GameState => next.scoreLog.push({name: 'Final Score', chips: chips, mult: mult, notes: `+$${state.moneyTotalLog}`}) next.stats.score += (chips * mult) next.active.score = {chips: chips, mult: mult} + + state.jokers.filter(j => j.joker.activation.includes(Activation.AfterScoring) && !j.debuffed).forEach(j => { + switch(j.joker.name) { + case 'Photograph': + j.joker.counter = 1 + break + } + }) } + next = {...next, stats: {...next.stats, hands: state.stats.hands - 1 @@ -1088,13 +1187,20 @@ export const gameReducer = (state: GameState, action: GameAction): GameState => state.jokers.filter(j => j.joker.activation.includes(Activation.OnDiscard) && !j.debuffed).forEach(j => { switch(j.joker.name) { case 'Faceless Joker': - if(state.cards.selected.reduce((face, c) => face += ([Rank.King, Rank.Queen, Rank.Jack].includes(c.rank) ? 1 : 0), 0)) { + if(state.cards.selected.reduce((face, c) => face += ([Rank.King, Rank.Queen, Rank.Jack].includes(c.rank) ? 1 : 0), 0) >= 3) { next.stats.money += 5 } break case 'Green Joker': j.joker.counter = Math.max(0, j.joker.counter! - 1); break + case 'Mail-In Rebate': + state.cards.selected.forEach(c => { + if(c.rank === j.joker.counter! + 2) { + next.stats.money += 5 + } + }) + break } }) next = {...next, diff --git a/src/Utilities.ts b/src/Utilities.ts index 57e61f7..d052568 100644 --- a/src/Utilities.ts +++ b/src/Utilities.ts @@ -198,9 +198,11 @@ export const newOffers = (slots: number, weights: { const validJokers = Jokers.filter(j => j.rarity === rarity && !game.jokers.find(joker => joker.joker.name === j.name) && !offers.filter(o => (o as JokerInstance).joker).find(o => (o as JokerInstance).joker.name === j.name)) if(validJokers.length === 0) { validJokers.push(Jokers[0])} + let joker = validJokers[Math.floor(Random.next() * validJokers.length)] offers.push({ id: -i, - joker: validJokers[Math.floor(Random.next() * validJokers.length)], + joker: joker, + counter: joker.counter, shopMode: true }) } else if(roll < (weights.Joker + weights.Tarot) / total) { diff --git a/src/assets/jokers/Common/Mail-In_Rebate.png b/src/assets/jokers/Common/Mail-In_Rebate.png new file mode 100644 index 0000000000000000000000000000000000000000..824c9945bea7dd758667677dc7c02bf4fd3b385d GIT binary patch literal 3481 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 F{{Y(XGTi_G literal 0 HcmV?d00001 diff --git a/src/assets/jokers/Common/Photograph.png b/src/assets/jokers/Common/Photograph.png new file mode 100644 index 0000000000000000000000000000000000000000..39c570867e4cba06282116d652bd71ad173dce60 GIT binary patch literal 9695 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 aN6bXlJlU*#lE;7ke^OP{QfQEahy4%Mw6yF1 literal 0 HcmV?d00001 diff --git a/src/assets/jokers/Common/Reserved_Parking.png b/src/assets/jokers/Common/Reserved_Parking.png new file mode 100644 index 0000000000000000000000000000000000000000..af73a7bc5fbce9bed12c3ba9d64bf66426fab238 GIT binary patch literal 2006 zcmY*a2{@bC8vcn|QZ?LS=nyH|Nv9;1aZ4&Rl?ZMlB6hXaRzfU^3dT}9wbj)!MQwdl zEz#6kMLU)b+K#4#(%RQDq39sh*8OR(x%d3ff4=v;-+SKgeCPR}=TEUPCmewug8~3> z#MA_52}V5lI*AH{^M+{E1Q>+8u|zBYurm*TaytaB;qE4uL;wgs2>>zi0Pqo{Vio}) zL<0bpTmb-`2LRs(7POG{!GwjUov9a*2>b+MQ9w}O9{>bI0^kEA`2a%u7yv*ga6pO$ z{>~N)9%S*wkOSI+}@5-dCVOyho#y;rkK>6{BoNw16801bf2&iPS)9C>ucGaJYW3hZousXZ&qD zxWXu3W-tQLC{$=@C^A$V84&D^($v$_LuqKCw6xSgg*rWq#&Bb*)95N+P5$eH^Q5~6 z`vfw40%-6(U$;vEAqr>}0EdcAaab#+0ME%W z_$XFVMcR8dzijQrae>o0vDF_K{qDogZys5@mAm*hc=;t+VaMBhHWt>C`Ic{*o^@WG zI8&=8oG=LuYUe!pxbu6cj*IW^UkkOFVH3=MIonHCV%^$b1+jKzn#1`oiQSiX)YqFA z@IkJ)s6k`44e76=s7hP&=Vh4~?oi|~G3A^LZcF8%!@^EYphE7IM5S?Q*(EUmM-tPc z)zNf}JIExS6fZ*8dV7x8dkc4`@jY*>t^xMq_fF{@`^xbWc2n%sh!;f9vqycP8)GwX}pg@HGsbC~?= z;-yv-NsLFK71bGRoBm3X<*HV-_GM!4vD&WfSHE^wEDhv$lv^00^+dd3%MMhlg@;|| zk)$Gn`B$VLsELK$ERDg}RHf@hJiHpKN|*eZUj`v3oOySAg5r_k)HoLb<+^VTHQ;am zUg_|(!921C^DvOBzr}f489BJRGnIc{5QO@G&(N~KXJ;y8Ui{5IPrMCF6nW!NOG zbGQ=kH=hzNNpN3$R*Nt%svRpWwn(BEtJ!eTL$Zw&vCQ@f?C;D>}xPRgSQB<8Cjm`L$c* zR8KB;X1u4qkWaO2n>RkDq}Qb5jerXK$S8#MNYO@qA(C&~=UtF|?i8g8frs;~pQzkz zv|UkK{ZO9ur;6w~*2w5tLN4O+;NiUME#7|d(M^al7JgnkSDf z$783o4Leaq-m-CZg{2l^_9QY+oJJy7#8=NX@v|cu(%Tc-&6?{pcX}bClrwXSv8~@- z;j?G{)Q+UQ44nJfOKfYf1~!_FzzBH4uKt$Xoc{4< zKfFFb*71j1j zLE0O2OF3bep4A$%T5Xx`t-1#;EvH6br@XrlGb(&4leANDa@~`kmd<)sio&_2J5EIq1x`&pL;iPUbK7N=(U;O=44A1!ayjW z#d1tl46+aB>%x0KHk40nXrHYLVq=D9?28bMDF}0Dy0Qz-wM*oJA~O>hobl;;n}mx~x{(x{TP%sz(9eU!k^I57HN!FKcG8EpLbIE*4T&D8 z^rIyAl{m%jlrqh2yUa*gBLxzZQhy5D{N*%t_g+{_bifrU_JaJqfvbu?u+_$=rBekh z)it^be(t@`lJSPw{>a0Oc`2^xNGN^2O>nfWu{PW+K_FZqD`K%XB19rY#Ay(A=_i?@ zY2(&#rm%&2~@bl3_}0;;3{2tura< zVcJfgf)hIvHl$p>(?jD=24D%431e*n<%aW?<} literal 0 HcmV?d00001 diff --git a/src/assets/jokers/Rare/Obelisk.png b/src/assets/jokers/Rare/Obelisk.png new file mode 100644 index 0000000000000000000000000000000000000000..f5af9896609cb88fcb55943878b87b1459ce0ade GIT binary patch literal 7441 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 P^G9WAPByDJdN$@i{_a`^ literal 0 HcmV?d00001 diff --git a/src/assets/jokers/Uncommon/Midas_Mask.png b/src/assets/jokers/Uncommon/Midas_Mask.png new file mode 100644 index 0000000000000000000000000000000000000000..ee4c43e49bc8f2518c6b8feeefe1a01d03f49595 GIT binary patch literal 6078 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 literal 0 HcmV?d00001 diff --git a/src/assets/jokers/Uncommon/Turtle_Bean.png b/src/assets/jokers/Uncommon/Turtle_Bean.png new file mode 100644 index 0000000000000000000000000000000000000000..6caedd378f557b2a73d854aebefbe8571e8781f6 GIT binary patch literal 4652 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 literal 0 HcmV?d00001 diff --git a/src/components/Blind.tsx b/src/components/Blind.tsx index 4aa5eec..645c913 100644 --- a/src/components/Blind.tsx +++ b/src/components/Blind.tsx @@ -1,4 +1,4 @@ -import { useContext } from 'react' +import { useContext, useRef } from 'react' import stake_icon from '../assets/white_stake.webp' import { Blinds, BlindType, handLevels, HandType } from '../Constants' import './Blind.css' @@ -12,6 +12,8 @@ type BlindProps = { export const Blind = ({ type, blind }: BlindProps) => { const { state: game, dispatch } = useContext(GameStateContext) + const gameRef = useRef(game); + gameRef.current = game const req = game.blind.base * blind.mult let req_display = req.toLocaleString() if(req_display.length > 11) { req_display = req.toExponential()} @@ -28,6 +30,16 @@ export const Blind = ({ type, blind }: BlindProps) => { most = (most[1].played < hand[1].played || most[1].chips * most[1].mult < hand[1].chips * hand[1].mult) ? hand : most ), Object.entries(handLevels)[12]) + const onBlindSelect = () => { + if(isCurrent && type === 'select'){ + console.log(game.stats, gameRef.current.stats) + dispatch({type: 'state', payload: {state: 'scoring'}}) + console.log(game.stats, gameRef.current.stats) + dispatch({type: 'draw', payload: {amount: gameRef.current.stats.handSize - gameRef.current.cards.hand.length}}) + console.log(game.stats, gameRef.current.stats) + } + } + return ( <> {type === 'sidebar' && <> @@ -61,17 +73,7 @@ export const Blind = ({ type, blind }: BlindProps) => {
-
{ - if(isCurrent && type === 'select'){ - dispatch({type: 'state', payload: {state: 'scoring'}}) - let draw = game.stats.handSize - if(game.blind.curr === 'boss' && game.blind.boss.name === 'The Manacle') { - dispatch({type: 'stat', payload: {stat: 'handSize'}}) - draw-- - } - dispatch({type: 'draw', payload: {amount: draw}}) - } - }}>{ +
{ isCurrent ? (type === 'select' ? 'Select' : 'Current') : ((game.blind.curr === 'boss' && Blinds.indexOf(blind) < 2) || (game.blind.curr === 'big' && Blinds.indexOf(blind) < 1)) ? 'Defeated' : 'Upcoming' }
diff --git a/src/components/Hand.tsx b/src/components/Hand.tsx index 6371a02..1e02e10 100644 --- a/src/components/Hand.tsx +++ b/src/components/Hand.tsx @@ -24,7 +24,6 @@ export default function Hand() {
0}`} onClick={() => { if(gameRef.current.cards.selected.length > 0) { - let selected = gameRef.current.cards.selected let len = Math.max(gameRef.current.stats.handSize - (gameRef.current.cards.hand.length - gameRef.current.cards.selected.length), 0) dispatch({type: 'submit'}) if(game.blind.curr === 'boss' && game.blind.boss.name === 'The Hook') { @@ -34,14 +33,6 @@ export default function Hand() { dispatch({type: 'updateCards', payload: {cardLocation: 'hidden', update: [...game.cards.hidden, ...discard]}}) len += discard.length } - if(game.jokers.find(j => j.joker.name === 'DNA') !== undefined && gameRef.current.cards.hidden.length === 0 && selected.length === 1) { - dispatch({type: 'addCard', payload: {cardLocation: 'hand', card: { - ...selected[0], - selected: false, - submitted: false - }}}) - len-- - } setTimeout(() => { const lastHand = game.active.name @@ -60,6 +51,8 @@ export default function Hand() { for(let i = 0; i < Math.min(game.stats.consumableSize - game.cards.consumables.length, planets); i++) { dispatch({type: 'addCard', payload: {card: Consumables.find(c => c.hand === lastHand)}}); } + } else if(gameRef.current.stats.hands === 0) { + // Game Over } else { dispatch({type: 'draw', payload: {amount: len, previous: 'played'}}) } diff --git a/src/components/Joker.tsx b/src/components/Joker.tsx index 7b15be0..b5963a3 100644 --- a/src/components/Joker.tsx +++ b/src/components/Joker.tsx @@ -32,6 +32,7 @@ export const Joker = ({id, joker, edition, selected = false, ...props}: JokerIns case 'Madness': case 'Square Joker': case 'Vampire': + case 'Obelisk': description = description.replace('_', joker.counter! + '') break case 'Abstract Joker': @@ -51,6 +52,8 @@ export const Joker = ({id, joker, edition, selected = false, ...props}: JokerIns let nines = fullDeck.reduce((nines, c) => nines += (c.rank === Rank.Nine ? 1 : 0), 0) description = description.replace('_', nines + '') break + case 'Mail-In Rebate': + description = description.replace('_', Rank[joker.counter!]) } const descriptionElement = description.split('\n').map((line, i) => diff --git a/src/components/JokerInfo.ts b/src/components/JokerInfo.ts index 77f0c0d..ac8440f 100644 --- a/src/components/JokerInfo.ts +++ b/src/components/JokerInfo.ts @@ -1,9 +1,11 @@ -import { Edition, Sticker } from "../Constants" +import { DeckType, Edition, Enhancement, Rank, Sticker, Suit } from "../Constants" +import { addCard, GameState, initialGameState, Random } from "../GameState" export type JokerInstance = { id: number joker: JokerType + counter?: number edition?: Edition sticker?: Sticker selected?: boolean @@ -12,7 +14,7 @@ export type JokerInstance = { shopMode?: boolean } -export enum Activation { OnPlayed, OnScored, OnHeld, Independent, OnOther, OnDiscard, EndOfRound, Passive, OnBlind } +export enum Activation { OnPlayed, OnScored, OnHeld, Independent, OnOther, OnDiscard, EndOfRound, Passive, OnBlind, AfterScoring } export type JokerType = { name: string @@ -20,6 +22,7 @@ export type JokerType = { cost: number rarity: 'Common' | 'Uncommon' | 'Rare' | 'Legendary' activation: Activation[] + activate: (game: GameState, joker: JokerInstance, act: Activation, mult?: number, chips?: number, ) => GameState counter?: number copyable?: boolean perishable?: boolean @@ -32,7 +35,12 @@ export const Jokers: JokerType[] = [ description: '{red}+4/Mult', cost: 2, rarity: 'Common', - activation: [Activation.Independent] + activation: [Activation.Independent], + activate: (game, _, __, mult) => { + mult! += 4 + game.scoreLog.push({name: 'Joker', mult: 4, mult_type: '+'}) + return game + } }, // { // name: 'Greedy Joker', @@ -164,13 +172,27 @@ export const Jokers: JokerType[] = [ // cost: 5, // rarity: 'Common', // activation: [Activation.Independent] - // }, { - // name: 'Marble Joker', - // description: 'Adds one /{orange}Stone/ card\n to the deck when\n{orange}Blind/ is selected', - // cost: 6, - // rarity: 'Uncommon', - // activation: [Activation.OnBlind] - // }, { + // }, + { + name: 'Marble Joker', + description: 'Adds one /{orange}Stone/ card\n to the deck when\n{orange}Blind/ is selected', + cost: 6, + rarity: 'Uncommon', + activation: [Activation.OnBlind], + activate: (game, _, __) => { + addCard({game, card: { + id: game.cards.nextId, + suit: Math.floor(Random.next() * Object.keys(Suit).length), + rank: Math.floor(Random.next() * Object.keys(Rank).length), + chips: 50, + enhancement: Enhancement.Stone, + deck: DeckType.Red + }, loc: 'deck'}) + console.log(game) + return game + } + }, + // { // name: 'Loyalty Card', // description: '{red-invert}X4/ Mult every/{orange}6\n hands played\n{grey}_ remaining', // cost: 5, @@ -279,13 +301,20 @@ export const Jokers: JokerType[] = [ // rarity: 'Common', // activation: [Activation.EndOfRound], // counter: 0 - // }, { - // name: 'Burglar', - // description: 'When/ {orange}Blind/ is selected,\n gain/ {blue}+3/ Hands and\n {orange}lose all discards', - // cost: 6, - // rarity: 'Uncommon', - // activation: [Activation.OnBlind] - // }, { + // }, + { + name: 'Burglar', + description: 'When/ {orange}Blind/ is selected,\n gain/ {blue}+3/ Hands and\n {orange}lose all discards', + cost: 6, + rarity: 'Uncommon', + activation: [Activation.OnBlind], + activate: (game, _, __) => { + game.stats.hands += 3 + game.stats.discards = 0 + return game + } + }, + // { // name: 'Blackboard', // description: '{red-invert}X3/ Mult if all cards held\n in hand are/ {dark-purple}Spades/ or/ {blue} Clubs', // cost: 6, @@ -311,8 +340,18 @@ export const Jokers: JokerType[] = [ description: 'If/ {orange}first hand/ of round\n has only/ {orange}1/ card, add a\n permanent copy to deck\n and draw it to/ {orange}hand', cost: 8, rarity: 'Rare', - activation: [] // Activated in hand on submit - }, + activation: [Activation.OnPlayed, Activation.EndOfRound], + activate: (game, joker, act) => { + if(act === Activation.OnPlayed && joker.counter! > 0 && game.cards.selected.length === 1) { + addCard({game, card: game.cards.selected[0], loc: 'hand'}) + joker.counter!-- + } else if(act === Activation.EndOfRound) { + joker.counter = 1 + } + return game + }, + counter: 1 + }, // { // name: 'Splash', // description: 'Every/ {orange}played card/ counts\n in scoring', @@ -384,71 +423,170 @@ export const Jokers: JokerType[] = [ cost: 7, rarity: 'Uncommon', activation: [Activation.OnBlind, Activation.Independent], + activate: (game, j, _) => { + if(game.blind.curr !== 'boss') { + j.counter! += 0.5 + let validJokers = game.jokers.filter(joker => joker !== j) + if(validJokers.length > 0) { + let target = validJokers[Math.floor(Random.next() * validJokers.length)].id + game.jokers = game.jokers.filter(j => j.id !== target) + } + } + return game + }, counter: 1 - }, { - name: 'Square Joker', - description: 'This Joker gains/ {blue}+4/ Chips if\n played hand has exactly/ {orange}4/ cards\n{grey}(Currently/ {blue}_/{grey}Chips)', - cost: 4, - rarity: 'Common', - activation: [Activation.OnPlayed, Activation.Independent], - counter: 0 - }, { - name: 'Seance', - description: 'If/ {orange}poker hand/ is a\n {orange}Straight Flush/{nospace}, create a\n random/ {blue}Spectral/ card\n {grey small}(Must have room)', - cost: 6, - rarity: 'Uncommon', - activation: [Activation.OnPlayed] - }, { + }, + // { + // name: 'Square Joker', + // description: 'This Joker gains/ {blue}+4/ Chips if\n played hand has exactly/ {orange}4/ cards\n{grey}(Currently/ {blue}_/{grey}Chips)', + // cost: 4, + // rarity: 'Common', + // activation: [Activation.OnPlayed, Activation.Independent], + // counter: 0 + // }, { + // name: 'Seance', + // description: 'If/ {orange}poker hand/ is a\n {orange}Straight Flush/{nospace}, create a\n random/ {blue}Spectral/ card\n {grey small}(Must have room)', + // cost: 6, + // rarity: 'Uncommon', + // activation: [Activation.OnPlayed] + // }, + { name: 'Riff-Raff', description: 'When/ {orange}Blind/ is selected,\n create/ {orange}2/ {blue}Common/ {orange}Jokers\n {small grey}(Must have room)', cost: 5, rarity: 'Common', - activation: [Activation.OnBlind] - }, { - name: 'Vampire', - description: 'This Joker gains/ {red}+/ {red-invert nospace}X0.1\n per scoring/ {orange}Enhanced\n {orange}card/ played, removes\n card/ {orange}Enhancement\n {grey}(Currently/ {red-invert}X_/ {grey}Mult)', - cost: 7, - rarity: 'Uncommon', - activation: [Activation.OnScored, Activation.Independent], - counter: 1 - }, { - name: 'Shortcut', - description: 'Allows/ {orange}Straights/ to be\n made with gaps of/ {orange}1 rank\n {grey}(ex:/ {orange}10 8 6 5 3/{grey nospace})', - cost: 7, - rarity: 'Uncommon', - activation: [Activation.Passive] - } // Hologram - , { - name: 'Vagabond', - description: 'Create a/ {purple}Tarot/ card\n if hand is played with\n {yellow}$4/ or less\n {small grey}(Must have room)', - cost: 8, - rarity: 'Rare', - activation: [Activation.OnPlayed] - }, { - name: 'Baron', - description: 'Each/ {orange}King/ held in hand\n gives/ {red-invert}X1.5/ Mult', - cost: 8, - rarity: 'Rare', - activation: [Activation.OnHeld] - }, { - name: 'Cloud 9', - description: 'Earn/ {yellow}$1/ for each/ {orange}9\n in your/ {orange}full deck/ at\n end of round\n {grey}(Currently/ {yellow}$_/ {grey nospace})', - cost: 7, - rarity: 'Uncommon', - activation: [Activation.EndOfRound] - } - // ,{ - // name: 'Baseball Card', - // description: '{green}Uncommon/Jokers each\ngive/{red-invert}X1.5/Mult', + activation: [Activation.OnBlind], + activate: (game, _, __) => { + if(game.jokers.length < game.stats.jokerSize) { + let validJokers = Jokers.filter(j => game.jokers.every(joker => joker.joker.name === j.name)) + let joker: JokerType + let nToAdd = Math.min(2, game.stats.jokerSize - game.jokers.length) + for(let i = 0; i < nToAdd; i++) { + if(validJokers.length === 0) { validJokers.push(Jokers[0]) } + joker = validJokers[Math.floor(Random.next() * validJokers.length)] + game = {...game, + jokers: [...game.jokers, { + id: game.cards.nextId + i, + joker: joker + }] + } + validJokers.filter(j => j.name !== joker.name) + } + game.cards.nextId + nToAdd + } + return game + } + }, + // { + // name: 'Vampire', + // description: 'This Joker gains/ {red}+/ {red-invert nospace}X0.1\n per scoring/ {orange}Enhanced\n {orange}card/ played, removes\n card/ {orange}Enhancement\n {grey}(Currently/ {red-invert}X_/ {grey}Mult)', + // cost: 7, + // rarity: 'Uncommon', + // activation: [Activation.OnScored, Activation.Independent], + // counter: 1 + // }, { + // name: 'Shortcut', + // description: 'Allows/ {orange}Straights/ to be\n made with gaps of/ {orange}1 rank\n {grey}(ex:/ {orange}10 8 6 5 3/{grey nospace})', + // cost: 7, + // rarity: 'Uncommon', + // activation: [Activation.Passive] + // } // Hologram + // , { + // name: 'Vagabond', + // description: 'Create a/ {purple}Tarot/ card\n if hand is played with\n {yellow}$4/ or less\n {small grey}(Must have room)', + // cost: 8, + // rarity: 'Rare', + // activation: [Activation.OnPlayed] + // }, { + // name: 'Baron', + // description: 'Each/ {orange}King/ held in hand\n gives/ {red-invert}X1.5/ Mult', + // cost: 8, + // rarity: 'Rare', + // activation: [Activation.OnHeld] + // }, { + // name: 'Cloud 9', + // description: 'Earn/ {yellow}$1/ for each/ {orange}9\n in your/ {orange}full deck/ at\n end of round\n {grey}(Currently/ {yellow}$_/ {grey nospace})', + // cost: 7, + // rarity: 'Uncommon', + // activation: [Activation.EndOfRound] + // }, { + // name: 'Rocket', + // description: 'Earn/ {yellow}$1/ at end of round.\n Payout increases by/ {yellow}$2/ when\n {orange}Boss Blind/ is defeated', + // cost: 6, + // rarity: 'Uncommon', + // activation: [Activation.EndOfRound], + // counter: 1 + // }, { + // name: 'Obelisk', + // description: 'This joker gains/ {red}+/{red-invert nospace}X0.2/ Mult\n per/ {orange}consecutive/ hand played without\n playing your most played\n {orange}poker hand/ {grey}(Currently/ {red-invert}X_/ {grey}Mult)', // cost: 8, // rarity: 'Rare', - // activation: [] + // activation: [Activation.OnPlayed, Activation.Independent], + // counter: 1 + // }, { + // name: 'Midas Mask', + // description: 'All played/ {orange}face\n cards become/ {orange}Gold\n cards when scored', + // cost: 7, + // rarity: 'Uncommon', + // activation: [Activation.OnScored] + // } // Luchador + // , { + // name: 'Photograph', + // description: 'First played/ {orange}face card\n gives/ {red-invert}X2/ Mult when scored', + // cost: 5, + // rarity: 'Common', + // activation: [Activation.OnScored, Activation.AfterScoring], + // counter: 1 + // }, { + // name: 'Gift Card', + // description: 'Add/ {yellow}$1/ of/ {orange} sell value\n to every/ {orange}Joker/ and\n {orange}Consumable/ card at end of round', + // cost: 6, + // rarity: 'Uncommon', + // activation: [Activation.EndOfRound] + // }, + { + name: 'Turtle Bean', + description: '{orange}+5/ hand size, reduces\n by/ {red}1/ each round', + cost: 6, + rarity: 'Uncommon', + activation: [Activation.OnBlind, Activation.EndOfRound], + activate: (game, j, act) => { + if(act === Activation.OnBlind && j.counter! > 0) { + game.stats.handSize += j.counter! + } else if (act === Activation.EndOfRound) { + game.stats.handSize = initialGameState.stats.handSize + j.counter!-- + } + return game + }, + counter: 5 + }, // Erosion + // { + // name: 'Reserved Parking', + // description: 'Each/ {orange}face/ card held in\n hand has a/ {green} 1 in 2\n chance to give/ {yellow}$1', + // cost: 6, + // rarity: 'Common', + // activation: [Activation.OnHeld] + // }, { + // name: 'Mail-In Rebate', + // description: 'Earn/ {yellow}$5/ for each\n discarded/ {orange}_/{nospace},\n rank changes every round', + // cost: 4, + // rarity: 'Common', + // activation: [Activation.OnDiscard, Activation.EndOfRound], + // counter: 0 + // } + // // ,{ + // // name: 'Baseball Card', + // // description: '{green}Uncommon/Jokers each\ngive/{red-invert}X1.5/Mult', + // // cost: 8, + // // rarity: 'Rare', + // // activation: [] + // // } + // , { + // name: 'Triboulet', + // description: 'Played Kings and\nQueens each give/{red-invert}X2/Mult\nwhen scored', + // cost: 20, + // rarity: 'Legendary', + // activation: [Activation.OnScored] // } - , { - name: 'Triboulet', - description: 'Played Kings and\nQueens each give/{red-invert}X2/Mult\nwhen scored', - cost: 20, - rarity: 'Legendary', - activation: [Activation.OnScored] - } ] \ No newline at end of file diff --git a/src/components/MainMenu.css b/src/components/MainMenu.css index 66c71a6..5a49f75 100644 --- a/src/components/MainMenu.css +++ b/src/components/MainMenu.css @@ -4,6 +4,11 @@ align-items: center; } +h1 { + font-size: 256px; + line-height: 32px; +} + #logo { width: 666px; } diff --git a/src/components/MainMenu.tsx b/src/components/MainMenu.tsx index 98b3030..cec9ede 100644 --- a/src/components/MainMenu.tsx +++ b/src/components/MainMenu.tsx @@ -1,5 +1,5 @@ import { useState } from 'react' -import logo from '../assets/logo.png' +// import logo from '../assets/logo.png' // import ace from '../assets/cards/SA.webp' // import cardBack from '../assets/cards/modifiers/enhancements/Base.png' import './MainMenu.css' @@ -10,7 +10,9 @@ export const MainMenu = () => { return (