diff --git a/CHANGELOG.md b/CHANGELOG.md index 6293552..e41a465 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +# v0.2.38 + +Blackjack arrives as a full table game with its own economy: every minigame now feeds a persistent chip bank you spend on buy-ins at the card tables. Poker gains named tables, popup history, and dev controls; mission briefings and side ops move to a proper rich text editor, and rank promotions get a ceiling-based authority model. + +### Features + +- **Blackjack**: take a seat at a four-seat oval felt with betting, insurance, double, and split. Chip piles stack on the rail by denomination, wins fly chips down to your pile while losses float up to the dealer, and fullscreen mode keeps the felt centered at any window size. Deal whooshes, turn chimes, and win stingers come with a sound toggle that remembers your choice. +- **Chip bank**: minigame XP now earns play chips (10 per XP), spent as buy-ins at the poker and blackjack tables. The balance card stays pinned in the corner while you scroll, pops the delta when your balance moves, flashes green or red with the direction, and plays a rising or falling chime. A daily top-up is there to claim when you dip low. +- **Poker upgrades**: tables carry proper names, action popups keep a replayable history, and a dev panel exposes table controls for testing. +- **Respawn tickets**: mission attendance converts into respawn tickets, settled automatically after each op with balances that accumulate over time. +- **Rank promotions**: promotion authority now derives from your rank's ceiling instead of a flat staff check, and command staff can promote directly from a member's profile. +- **Mission briefings**: briefings and side-op narratives use a rich text editor with a formatting toolbar, inline wikilinks, and live preview; comms bodies render with matching styles. +- **Voiceover**: recordings gain a spoiler gate so unreleased content stays hidden until its time, plus clause-aware pause pacing. +--- # v0.2.36 Poker takes the spotlight in this stretch: a rebuilt table, synthesized sound, card skins, and glowing hand ranks. Alongside it, the awards program learns advancement series, and poker placement XP is paused while payouts get reworked; placements, hands won, and best chips still record as normal. diff --git a/src/app/(frontend)/styles.css b/src/app/(frontend)/styles.css index 4121c07..e8e683a 100644 --- a/src/app/(frontend)/styles.css +++ b/src/app/(frontend)/styles.css @@ -1378,6 +1378,30 @@ transform: translate(-50%, -50%); } +/* Blackjack seats share the poker seat panel CSS, whose commit pill and hand + reveal are absolutely positioned via poker-only arc classes that blackjack + slots never carry. Keep the pill in the panel row and push corner-seat + reveals outward, clear of the dealer block. */ +.blackjack-felt .poker-seat-commit { + position: static; + transform: none; +} + +.blackjack-felt .blackjack-seat-arc-corner-right .poker-seat-reveal { + left: calc(50% + 4.5rem); +} + +.blackjack-felt .blackjack-seat-arc-corner-left .poker-seat-reveal { + left: calc(50% - 4.5rem); +} + +/* Top-anchor the log below the dealer block (bottom edge reaches ~44% with + the turn clock) so the newest line can never climb over the time bar. */ +.blackjack-felt .poker-action-log { + top: 46%; + bottom: auto; +} + .poker-felt-fullscreen { min-height: max(76vh, 42rem); border-radius: 50% / 48%; diff --git a/src/components/frontend/minigames/blackjack/BlackjackActionToolbar.tsx b/src/components/frontend/minigames/blackjack/BlackjackActionToolbar.tsx index d5423d1..afe3ea4 100644 --- a/src/components/frontend/minigames/blackjack/BlackjackActionToolbar.tsx +++ b/src/components/frontend/minigames/blackjack/BlackjackActionToolbar.tsx @@ -1,6 +1,7 @@ "use client"; import type { BlackjackSnapshot } from "@/app/(frontend)/minigames/blackjack/actions"; +import { cn } from "@/lib/utils"; import { BlackjackChipStack } from "./BlackjackChipStack"; import { BlackjackControls } from "./BlackjackControls"; @@ -12,18 +13,22 @@ interface BlackjackActionToolbarProps { readonly snapshot: SeatedSnapshot; readonly onSnapshot: (snapshot: BlackjackSnapshot) => void; readonly onActionFeedback: () => void; + readonly below?: boolean; } /** * Minimal felt overlay: one bottom-centered column holding the bankroll * pill plus either the waiting pill or the acting player's controls. * Rendering them as a single stack keeps the pair collision-free at every - * phase; on a settled round only the bankroll pill remains. + * phase; on a settled round only the bankroll pill remains. With `below`, + * the same stack renders in normal flow under the felt so narrow screens + * never clip it. */ export function BlackjackActionToolbar({ snapshot, onSnapshot, onActionFeedback, + below = false, }: BlackjackActionToolbarProps) { const view = snapshot.you; const viewerPlayer = view.players.find((player) => player.seatId === view.viewerSeat); @@ -58,14 +63,21 @@ export function BlackjackActionToolbar({ if (settled) { return ( -
+
{bankrollPill}
); } return ( -
+
{bankrollPill} {!view.yourTurn ? ( @@ -74,9 +86,7 @@ export function BlackjackActionToolbar({ role="status" > {(() => { - const actingPlayer = view.players.find( - (player) => player.seatId === view.activeSeat, - ); + const actingPlayer = view.players.find((player) => player.seatId === view.activeSeat); return actingPlayer ? `Waiting for ${actingPlayer.name}` : "Waiting for the table"; })()} diff --git a/src/components/frontend/minigames/blackjack/BlackjackFeltCanvas.tsx b/src/components/frontend/minigames/blackjack/BlackjackFeltCanvas.tsx index 6b9020f..47a7c77 100644 --- a/src/components/frontend/minigames/blackjack/BlackjackFeltCanvas.tsx +++ b/src/components/frontend/minigames/blackjack/BlackjackFeltCanvas.tsx @@ -64,6 +64,17 @@ export function BlackjackFeltCanvas({ const tableAnnouncements = popups.filter((popup) => popup.tone === "leave"); const liveTurn = view.phase !== "round-complete"; + // Narrow screens render the action toolbar below the felt in flow: the + // overlay pill row is wider than the felt there and the felt clips it. + const [toolbarBelow, setToolbarBelow] = useState(false); + useEffect(() => { + const query = window.matchMedia("(max-width: 640px)"); + const update = () => setToolbarBelow(query.matches); + update(); + query.addEventListener("change", update); + return () => query.removeEventListener("change", update); + }, []); + // Chip flight: on the settle transition, chips launch one after another // from the hand spot with denomination colors matching the money moved: // payouts (and pushes) toward the bankroll pill, lost bets up to the @@ -264,7 +275,7 @@ export function BlackjackFeltCanvas({
)} - {!spectator && ( + {!spectator && !toolbarBelow && ( )}
+ + {!spectator && toolbarBelow && ( + + )}
); } diff --git a/src/components/frontend/minigames/blackjack/BlackjackSeat.tsx b/src/components/frontend/minigames/blackjack/BlackjackSeat.tsx index ea773b0..d9942f9 100644 --- a/src/components/frontend/minigames/blackjack/BlackjackSeat.tsx +++ b/src/components/frontend/minigames/blackjack/BlackjackSeat.tsx @@ -121,32 +121,34 @@ export function BlackjackSeat({ )}
- {player.hands.map((hand, handIndex) => ( -
1 && "opacity-80", - )} - aria-label={`Hand ${handIndex + 1}: ${handValue(hand.cards).total}${ - hand.doubled ? ", doubled" : "" - }`} - > - {hand.cards.map((card, cardIndex) => ( - - ))} - - {handValue(hand.cards).total} - -
- ))} + {player.hands + .filter((hand) => hand.cards.length > 0) + .map((hand, handIndex) => ( +
1 && "opacity-80", + )} + aria-label={`Hand ${handIndex + 1}: ${handValue(hand.cards).total}${ + hand.doubled ? ", doubled" : "" + }`} + > + {hand.cards.map((card, cardIndex) => ( + + ))} + + {handValue(hand.cards).total} + +
+ ))} ); }