diff --git a/src/GameState.ts b/src/GameState.ts index d021f87..7d26329 100644 --- a/src/GameState.ts +++ b/src/GameState.ts @@ -73,6 +73,13 @@ export type GameState = { mult: number } } + + scoreLog: { + name: string, + chips?: number, + mult?: number, + mult_type?: '+' | 'x' + }[] } export type GameAction = { @@ -107,9 +114,9 @@ export const initialGameState: GameState = { stats: { handSize: 8, hands: 4, - discards: 4, + discards: 40, money: 400, - ante: 8, + ante: 1, round: 0, score: 0, consumableSize: 2, @@ -165,7 +172,9 @@ export const initialGameState: GameState = { chips: 0, mult: 0 } - } + }, + + scoreLog: [] } let cerulean_bell_card: CardInfo @@ -193,9 +202,9 @@ export const gameReducer = (state: GameState, action: GameAction): GameState => id: i, suit: Suit[suits[Math.floor(Random.next()*suits.length)]], rank: Rank[ranks[Math.floor(Random.next()*ranks.length)]], - edition: Random.next() > .8 ? Edition[editions[Math.floor(Random.next()*editions.length)]] : undefined, - enhancement: Random.next() > .8 ? Enhancement[enhancements[Math.floor(Random.next()*enhancements.length)]]: undefined, - seal: Random.next() > .8 ? Seal[seals[Math.floor(Random.next()*seals.length)]]: undefined, + edition: Random.next() > .18 ? Edition[editions[Math.floor(Random.next()*editions.length)]] : undefined, + enhancement: Random.next() > .18 ? Enhancement[enhancements[Math.floor(Random.next()*enhancements.length)]]: undefined, + seal: Random.next() > .18 ? Seal[seals[Math.floor(Random.next()*seals.length)]]: undefined, deck: DeckType.Erratic } ) @@ -367,10 +376,14 @@ export const gameReducer = (state: GameState, action: GameAction): GameState => (name === 'The Mouth' && state.cards.played.length > 0 && !state.cards.played.includes(state.active.name)))) { next = {...next, active: initialGameState.active} } else { + next.scoreLog = [] + let hand = state.active.name handLevels[hand].played++ let chips = handLevels[hand].chips, mult = handLevels[hand].mult + next.scoreLog.push({name: HandType[hand], chips: chips, mult: mult}) + // Relevant boss mechanics if(state.blind.curr === 'boss') { if(name === 'The Arm') { @@ -380,6 +393,7 @@ export const gameReducer = (state: GameState, action: GameAction): GameState => } else if(name === 'The Flint') { chips = Math.ceil(chips / 2.0) mult = Math.ceil(mult / 2.0) + next.scoreLog.push({name: 'The Flint', chips: -chips, mult: -mult, mult_type: '+'}) } else if(name.match('The\ [Eye|Mouth]')) { next.cards.played.push(hand) } else if(name === 'The Tooth') { @@ -411,102 +425,186 @@ export const gameReducer = (state: GameState, action: GameAction): GameState => if(c.enhancement === Enhancement?.Stone) { c.scored = true } }) // Activation sequence - const baseball = state.jokers.find(j => j.joker.name === 'Baseball Card') !== undefined + const baseballCard = state.jokers.find(j => j.joker.name === 'Baseball Card') + const baseball = baseballCard !== undefined && !baseballCard.debuffed - state.jokers.filter(j => j.joker.activation.includes(Activation.OnPlayed)).forEach(j => { + state.jokers.filter(j => j.joker.activation.includes(Activation.OnPlayed) && !j.debuffed).forEach(j => { switch(j.joker.name) { } - if(baseball && j.joker.rarity === 'Uncommon') { mult *= 1.5 } + if(baseball && j.joker.rarity === 'Uncommon') { + mult *= 1.5 + next.scoreLog.push({name: 'Baseball Card', mult: 1.5, mult_type: 'x'}) + } }) selected.forEach(c => { if(!c.debuffed && c.scored) { + const cardName = `${c.edition !== undefined ? Edition[c.edition] + ' ' : ''}${c.enhancement !== undefined ? Enhancement[c.enhancement] + ' ' : ''}${c.seal !== undefined ? Seal[c.seal] + ' Seal ': ''}${c.enhancement === Enhancement?.Stone ? 'Card' : `${Rank[c.rank]} of ${Suit[c.suit]}`}` + next.scoreLog.push({name: cardName}) let triggers = 1 + (c.seal === Seal?.Red ? 1 : 0) for(let i = 0; i < triggers; i++) { - chips += rankChips[Rank[c.rank] as keyof typeof rankChips] - if(c.enhancement !== undefined && c.enhancement === Enhancement.Bonus) { chips += 30 } + if(c.enhancement !== Enhancement?.Stone) { + const rankChip = rankChips[Rank[c.rank] as keyof typeof rankChips] + chips += rankChip + next.scoreLog.push({name: Rank[c.rank], chips: rankChip}) + } + if(c.enhancement !== undefined && c.enhancement === Enhancement.Bonus) { + chips += 30 + next.scoreLog.push({name: 'Bonus Card', chips: 30}) + } if(c.enhancement !== undefined) { switch(c.enhancement) { - case Enhancement.Bonus: chips += 30; break case Enhancement.Glass: mult *= 2; - if(Random.next() < .25) { glassToBreak.push(c) } + next.scoreLog.push({name: 'Glass Card', mult: 2, mult_type: 'x'}) + if(Random.next() < .25) { + glassToBreak.push(c) + // TODO: Log broken glass? + } break case Enhancement.Lucky: - if(Random.next() < .2) { mult += 20 } + if(Random.next() < .2) { + mult += 20 + next.scoreLog.push({name: 'Lucky Card', mult: 20, mult_type: '+'}) + } if(Random.next() < .07) { next.stats.money += 20 } + // TODO: Log money? + break + case Enhancement.Mult: + mult += 4; + next.scoreLog.push({name: 'Mult Card', mult: 4, mult_type: '+'}) + break + case Enhancement.Stone: + chips += 50; + next.scoreLog.push({name: 'Stone Card', chips: 50}) break - case Enhancement.Mult: mult += 4; break - case Enhancement.Stone: chips += 50; break } } if(c.seal !== undefined && c.seal === Seal.Gold) { next.stats.money += 3 + // TODO: Log money? } if(c.edition !== undefined) { switch(c.edition) { - case Edition.Foil: chips += 50; break - case Edition.Holographic: mult += 10; break - case Edition.Polychrome: mult *= 1.5; break + case Edition.Foil: + chips += 50; + next.scoreLog.push({name: 'Foil', chips: 50}) + break + case Edition.Holographic: + mult += 10; + next.scoreLog.push({name: 'Holographic', mult: 10, mult_type: '+'}) + break + case Edition.Polychrome: + mult *= 1.5; + next.scoreLog.push({name: 'Polychrome', mult: 1.5, mult_type: 'x'}) + break } } - state.jokers.filter(j => j.joker.activation.includes(Activation.OnScored)).forEach(j => { + state.jokers.filter(j => j.joker.activation.includes(Activation.OnScored) && !j.debuffed).forEach(j => { switch(j.joker.name) { case 'Triboulet': - if([Rank.King, Rank.Queen].includes(c.rank)) { mult *= 2 } + if([Rank.King, Rank.Queen].includes(c.rank)) { + mult *= 2 + next.scoreLog.push({name: 'Triboulet', mult: 2, mult_type: 'x'}) + } break } - if(baseball && j.joker.rarity === 'Uncommon') { mult *= 1.5 } + if(baseball && j.joker.rarity === 'Uncommon') { + mult *= 1.5 + next.scoreLog.push({name: 'Baseball Card', mult: 1.5, mult_type: 'x'}) + } }) + if(c.seal === Seal?.Red && i < 1) { + next.scoreLog.push({name: 'Red Seal'}) + } + // Retrigger jokers } } }) - state.cards.hand.filter(c => !c.selected).forEach(c => { + state.cards.hand.filter(c => !c.selected && !c.submitted).forEach(c => { if(!c.debuffed) { - let triggers = 1 + (c.seal === Seal?.Red ? 1 : 0) - for(let i = 0; i < triggers; i++) { - if(c.enhancement === Enhancement?.Steel) { mult *= 1.5 } + let will_trigger = c.enhancement === Enhancement?.Steel + state.jokers.filter(j => j.joker.activation.includes(Activation.OnHeld) && !j.debuffed).forEach(j => { + switch(j.joker.name) { + + } + }) - state.jokers.filter(j => j.joker.activation.includes(Activation.OnHeld)).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}) + let triggers = 1 + (c.seal === Seal?.Red ? 1 : 0) + for(let i = 0; i < triggers; i++) { + if(c.enhancement === Enhancement?.Steel) { + mult *= 1.5 + next.scoreLog.push({name: 'Steel Card', mult: 1.5, mult_type: 'x'}) } - if(baseball && j.joker.rarity === 'Uncommon') { mult *= 1.5 } - }) - // Retrigger jokers + state.jokers.filter(j => j.joker.activation.includes(Activation.OnHeld) && !j.debuffed).forEach(j => { + switch(j.joker.name) { + + } + if(baseball && j.joker.rarity === 'Uncommon') { + mult *= 1.5 + next.scoreLog.push({name: 'Baseball Card', mult: 1.5, mult_type: 'x'}) + } + }) + + if(c.seal === Seal?.Red && i < 1) { + next.scoreLog.push({name: 'Red Seal'}) + } + + // Retrigger jokers + } } } }) - state.jokers.forEach(j => { - if(j.edition === Edition?.Foil) { chips += 50 } - if(j.edition === Edition?.Holographic) { mult += 10 } + state.jokers.filter(j => !j.debuffed).forEach(j => { + if(j.edition === Edition?.Foil) { + chips += 50 + next.scoreLog.push({name: `${j.joker.name + (j.joker.name.match(/.*s$/) ? '\'' : '\'s') + ' Foil'}`, chips: 50}) + } + if(j.edition === Edition?.Holographic) { + mult += 10 + next.scoreLog.push({name: `${j.joker.name + (j.joker.name.match(/.*s$/) ? '\'' : '\'s') + ' Holographic'}`, mult: 10, mult_type: '+'}) + } }) - state.jokers.filter(j => j.joker.activation.includes(Activation.Independent)).forEach(j => { + state.jokers.filter(j => j.joker.activation.includes(Activation.Independent) && !j.debuffed).forEach(j => { switch(j.joker.name) { - case 'Joker': mult += 4; break + case 'Joker': + mult += 4; + next.scoreLog.push({name: 'Joker', mult: 4, mult_type: '+'}) + break + } + if(baseball && j.joker.rarity === 'Uncommon') { + mult *= 1.5 + next.scoreLog.push({name: 'Baseball Card', mult: 1.5, mult_type: 'x'}) } - if(baseball && j.joker.rarity === 'Uncommon') { mult *= 1.5 } }) - state.jokers.forEach(j => { - if(j.edition === Edition?.Polychrome) { mult *= 1.5 } + state.jokers.filter(j => !j.debuffed).forEach(j => { + if(j.edition === Edition?.Polychrome) { + mult *= 1.5 + next.scoreLog.push({name: `${j.joker.name + (j.joker.name.match(/.*s$/) ? '\'' : '\'s') + ' Polychrome'}`, mult: 1.5, mult_type: 'x'}) + } }) chips = Math.ceil(chips), mult = Math.ceil(mult) + next.scoreLog.push({name: 'Final Score', chips: chips, mult: mult}) next.stats.score += (chips * mult) next.active.score = {chips: chips, mult: mult} } + console.log(next.scoreLog) next = {...next, stats: {...next.stats, hands: state.stats.hands - 1 diff --git a/src/components/Card.tsx b/src/components/Card.tsx index 9d4b6e6..d0b02e1 100644 --- a/src/components/Card.tsx +++ b/src/components/Card.tsx @@ -64,12 +64,12 @@ export const Card = ({ const popupTags = game.state === 'scoring' && debuffed ?
Debuffed
: <> - {enhancement !== undefined && enhancement !== Enhancement.Base && -
{`${Enhancement[enhancement]} Card`}
- } {edition !== undefined &&
{Edition[edition]}
} + {enhancement !== undefined && enhancement !== Enhancement.Base && +
{`${Enhancement[enhancement]} Card`}
+ } {seal !== undefined &&
{`${Seal[seal]} Seal`}
} diff --git a/src/components/DeckMenu.css b/src/components/DeckMenu.css index 6030631..a54bc30 100644 --- a/src/components/DeckMenu.css +++ b/src/components/DeckMenu.css @@ -141,7 +141,7 @@ margin: 4px; } -tr { +#suits tr { display: flex; flex-direction: row; } diff --git a/src/components/InfoPanel.tsx b/src/components/InfoPanel.tsx index 4ea13f1..c243864 100644 --- a/src/components/InfoPanel.tsx +++ b/src/components/InfoPanel.tsx @@ -7,7 +7,7 @@ import { Options } from './Options' export const InfoPanel = () => { const { state: game } = useContext(GameStateContext) const [ runMenu, setRunMenu ] = useState(false) - const [ optionsMenu, setOptionsMenu ] = useState(true) + const [ optionsMenu, setOptionsMenu ] = useState(false) return (
diff --git a/src/components/Round.css b/src/components/Round.css index ac91b6f..dc6c210 100644 --- a/src/components/Round.css +++ b/src/components/Round.css @@ -35,6 +35,10 @@ margin: 0 8px; } +#score-display:hover { + cursor: pointer; +} + #stake-icon { width: 24px; height: 24px; diff --git a/src/components/Round.tsx b/src/components/Round.tsx index 310ac51..eea418a 100644 --- a/src/components/Round.tsx +++ b/src/components/Round.tsx @@ -1,17 +1,21 @@ -import { useContext } from 'react' +import { useContext, useState } from 'react' import stake_icon from '../assets/white_stake.webp' import { GameStateContext } from '../GameState' import './Round.css' +import { ScoreLog } from './ScoreLog' export const Round = () => { const { state: game } = useContext(GameStateContext) + const [ logMenu, setLogMenu ] = useState(false) + return (
Round
score
-
+
setLogMenu(true)}>
{game.stats.score}
+ {logMenu && }
) } diff --git a/src/components/ScoreLog.css b/src/components/ScoreLog.css new file mode 100644 index 0000000..af4b358 --- /dev/null +++ b/src/components/ScoreLog.css @@ -0,0 +1,41 @@ +#score-log-outline { + position: absolute; + z-index: 1; + background-color: var(--light-grey); + border-radius: 8px; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +#score-log { + background-color: var(--grey); + border-radius: 8px; + margin: 4px; + width: 512px; + max-height: 640px; + overflow: scroll; +} + +#score-log > table { + font-size: 20px; + border-collapse: collapse; +} + +#score-log > table > tr { + border-bottom: 1px solid aliceblue; +} + +#score-log > table > tr:last-child { border: none } + +#score-log > table > #headings { + font-size: 32px; +} + +#score-log-back { + text-align: center; + font-size: 32px; + background-color: var(--orange); + border-radius: 8px; + margin: 2px; +} \ No newline at end of file diff --git a/src/components/ScoreLog.tsx b/src/components/ScoreLog.tsx new file mode 100644 index 0000000..b389179 --- /dev/null +++ b/src/components/ScoreLog.tsx @@ -0,0 +1,54 @@ +import { useContext } from "react" +import { GameStateContext } from "../GameState" +import './ScoreLog.css' + +type ScoreLogProps = { + setMenu: React.Dispatch> +} + +export const ScoreLog = (props: ScoreLogProps) => { + const { state: game } = useContext(GameStateContext) + + const chipFormat = (chips: number | undefined, mult: number | undefined, mult_type: string | undefined) => { + if(chips !== undefined) { + if(mult !== undefined && mult_type === undefined) { return {chips}} + return {`+${chips}`} + } + return + } + + const multFormat = (mult: number | undefined, mult_type: string | undefined) => { + if(mult !== undefined) { + if(mult < 0) { return {mult} } + if(mult_type === undefined) { return {mult}} + if(mult_type === '+') { return {`+${mult}`}} + return {`X${mult}`} + } + return + } + + return ( +
+
+ + + + + + + {game.scoreLog.map((entry, i) => ( + entry.chips === undefined && entry.mult === undefined ? + : + + + {chipFormat(entry.chips, entry.mult, entry.mult_type)} + {multFormat(entry.mult, entry.mult_type)} + + ) + )} +
NameChipsMult
{entry.name}
{entry.name}
+
+
props.setMenu(false)}>Back
+
+ ) +} \ No newline at end of file diff --git a/src/components/UseConsumable.ts b/src/components/UseConsumable.ts index 43a65bf..2650465 100644 --- a/src/components/UseConsumable.ts +++ b/src/components/UseConsumable.ts @@ -220,7 +220,7 @@ export const useConsumable = (game: GameState, dispatch: React.Dispatch j.edition === undefined) if(WoFJokers.length === 0) { return false } - if(Random.next() < 2.25) { + if(Random.next() < .25) { const joker = WoFJokers[Math.floor(Random.next() * WoFJokers.length)] switch(Math.floor(Random.next() * 3)) { case 0: joker.edition = Edition.Foil; break