@adiakys/feeling-lucky 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +53 -1
  2. package/dist/config/types.d.ts +5 -0
  3. package/dist/{de-B56NsnDF.js → de-CmzpGbNK.js} +11 -1
  4. package/dist/developer/panel.d.ts +1 -0
  5. package/dist/developer/settings.d.ts +1 -0
  6. package/dist/{es-9iWwCe8s.js → es-k_kS6Fn2.js} +11 -1
  7. package/dist/feeling-lucky.iife.js +395 -243
  8. package/dist/feeling-lucky.js +17 -41
  9. package/dist/{fr-Y2BcCS3U.js → fr-GuCZB1l4.js} +11 -1
  10. package/dist/games/cards/table.d.ts +3 -1
  11. package/dist/{i18n-it2FlmVZ.js → i18n-Cid8bj2R.js} +15 -5
  12. package/dist/icons-DTaPp44c.js +863 -0
  13. package/dist/{it-CNSOLgaT.js → it-BNztlqHd.js} +11 -1
  14. package/dist/locales/de/cards.d.ts +7 -0
  15. package/dist/locales/de/developer.d.ts +3 -0
  16. package/dist/locales/en/cards.d.ts +7 -0
  17. package/dist/locales/en/developer.d.ts +3 -0
  18. package/dist/locales/es/cards.d.ts +7 -0
  19. package/dist/locales/es/developer.d.ts +3 -0
  20. package/dist/locales/fr/cards.d.ts +7 -0
  21. package/dist/locales/fr/developer.d.ts +3 -0
  22. package/dist/locales/it/cards.d.ts +7 -0
  23. package/dist/locales/it/developer.d.ts +3 -0
  24. package/dist/mount-CMm0qSYk.js +6257 -0
  25. package/dist/multiplayer/blackjack.d.ts +35 -0
  26. package/dist/multiplayer/client.d.ts +55 -0
  27. package/dist/multiplayer/holdem.d.ts +21 -0
  28. package/dist/multiplayer/index.d.ts +2 -0
  29. package/dist/multiplayer/seats.d.ts +16 -0
  30. package/dist/multiplayer/shared.d.ts +33 -0
  31. package/dist/multiplayer-CN0t0j_F.js +502 -0
  32. package/dist/{panel-tWJMt9kl.js → panel-BVgq3Cm5.js} +158 -145
  33. package/dist/resolve-Dc48n2Jo.js +28 -0
  34. package/dist/room/room.d.ts +7 -1
  35. package/dist/runtime/context.d.ts +2 -1
  36. package/package.json +2 -2
  37. package/dist/mount-CBUkAcVV.js +0 -7109
@@ -0,0 +1,35 @@
1
+ import type { Tier } from '../config/types';
2
+ import '../room/chips';
3
+ import type { SharedSeat, TableView } from './client';
4
+ import { SharedTableElement } from './shared';
5
+ export declare class SharedBlackjack extends SharedTableElement {
6
+ protected readonly game = "blackjack";
7
+ private chosen;
8
+ private chips;
9
+ private history;
10
+ private lastBet;
11
+ protected willUpdate(): void;
12
+ protected betting(previous: TableView | null, view: TableView): void;
13
+ private get open();
14
+ private get turn();
15
+ private get hand();
16
+ private get theirs();
17
+ private beats;
18
+ private bet;
19
+ private undo;
20
+ private rebet;
21
+ private clearChips;
22
+ private deal;
23
+ protected outcome(mine: SharedSeat): {
24
+ game: 'blackjack';
25
+ tier: Tier;
26
+ prizeId: string;
27
+ award: import("../engine/awards").Award;
28
+ detail: {
29
+ key: string;
30
+ };
31
+ };
32
+ private hands;
33
+ private chipsOf;
34
+ render(): import("lit-html").TemplateResult<1>;
35
+ }
@@ -0,0 +1,55 @@
1
+ import type { Multiplayer, Player, Tier } from '../config/types';
2
+ import type { Card } from '../engine/cards';
3
+ export type SharedGame = 'blackjack' | 'holdem';
4
+ export interface TableView {
5
+ game: SharedGame;
6
+ round: number;
7
+ phase: 'betting' | 'dealing' | 'acting' | 'dealer' | 'done';
8
+ deadline: number | null;
9
+ boost: number;
10
+ you: number | null;
11
+ dealer: (Card | null)[];
12
+ board: (Card | null)[];
13
+ seats: (SharedSeat | null)[];
14
+ }
15
+ export interface SharedHand {
16
+ cards: (Card | null)[];
17
+ stacks: number;
18
+ done: boolean;
19
+ }
20
+ export interface SharedSeat {
21
+ name: string | null;
22
+ avatar: string | null;
23
+ ready: boolean;
24
+ playing: boolean;
25
+ prize: string | null;
26
+ chips: number;
27
+ hands: SharedHand[];
28
+ active: number;
29
+ folded: boolean;
30
+ decided: boolean;
31
+ result: string | null;
32
+ tier: Tier | null;
33
+ }
34
+ export declare function events(body: ReadableStream<Uint8Array>): AsyncGenerator<TableView>;
35
+ export declare class SharedTable {
36
+ server: Multiplayer;
37
+ readonly game: SharedGame;
38
+ private memory;
39
+ private connections;
40
+ constructor(server: Multiplayer, game: SharedGame);
41
+ private get key();
42
+ private get token();
43
+ private set token(value);
44
+ private request;
45
+ private reconnect;
46
+ listen(onView: (view: TableView) => void, signal: AbortSignal): Promise<void>;
47
+ sit(seat: number, player: Player | null): Promise<void>;
48
+ stand(): Promise<void>;
49
+ private leave;
50
+ act(action: string, details?: {
51
+ prize?: string;
52
+ chips?: number;
53
+ }): Promise<boolean>;
54
+ }
55
+ export declare function sharedTable(server: Multiplayer, game: SharedGame): SharedTable;
@@ -0,0 +1,21 @@
1
+ import type { Tier } from '../config/types';
2
+ import type { SharedSeat } from './client';
3
+ import { SharedTableElement } from './shared';
4
+ export declare class SharedHoldem extends SharedTableElement {
5
+ protected readonly game = "holdem";
6
+ private handName;
7
+ private made;
8
+ protected outcome(mine: SharedSeat): {
9
+ game: 'holdem';
10
+ tier: Tier;
11
+ prizeId: string;
12
+ award: import("../engine/awards").Award;
13
+ detail: {
14
+ key: string;
15
+ params: {
16
+ hand: string;
17
+ };
18
+ };
19
+ };
20
+ render(): import("lit-html").TemplateResult<1>;
21
+ }
@@ -0,0 +1,2 @@
1
+ import './blackjack';
2
+ import './holdem';
@@ -0,0 +1,16 @@
1
+ import { nothing, type TemplateResult } from 'lit';
2
+ import type { Card } from '../engine/cards';
3
+ import type { RoomContext } from '../runtime/context';
4
+ import type { SharedSeat, TableView } from './client';
5
+ export declare const BACK: Card;
6
+ export declare const cardOf: (dealt: Card | null, options?: {
7
+ lit?: boolean;
8
+ }) => TemplateResult<1>;
9
+ export declare function tableSeats(room: RoomContext, view: TableView, { cards, chips, outcome, sit, stand, }: {
10
+ cards: (seat: SharedSeat, mine: boolean) => TemplateResult | typeof nothing;
11
+ chips?: (seat: SharedSeat, mine: boolean) => TemplateResult | typeof nothing;
12
+ outcome: (seat: SharedSeat) => 'won' | 'lost' | null;
13
+ sit: ((seat: number) => void) | null;
14
+ stand: (() => void) | null;
15
+ }): TemplateResult<1>;
16
+ export declare const secondsLeft: (deadline: number | null) => number | null;
@@ -0,0 +1,33 @@
1
+ import type { Outcome } from '../engine/outcome';
2
+ import type { GameOptions } from '../runtime/context';
3
+ import { LuckyElement } from '../runtime/element';
4
+ import { type SharedGame, type SharedSeat, type SharedTable, type TableView } from './client';
5
+ export declare abstract class SharedTableElement extends LuckyElement {
6
+ options: GameOptions;
7
+ protected view: TableView | null;
8
+ protected offline: boolean;
9
+ protected clearing: boolean;
10
+ private felt?;
11
+ protected abstract readonly game: SharedGame;
12
+ protected table: SharedTable;
13
+ private stop;
14
+ private next;
15
+ private ticker;
16
+ private finished;
17
+ constructor();
18
+ protected get mine(): SharedSeat | null;
19
+ protected get canSit(): boolean;
20
+ protected sit: (seat: number) => void;
21
+ protected get canStand(): boolean;
22
+ protected stand: () => void;
23
+ connectedCallback(): void;
24
+ disconnectedCallback(): void;
25
+ protected act(action: string, details?: {
26
+ prize?: string;
27
+ chips?: number;
28
+ }): void;
29
+ private receive;
30
+ private show;
31
+ protected betting(_previous: TableView | null, _view: TableView): void;
32
+ protected abstract outcome(mine: SharedSeat): Outcome;
33
+ }
@@ -0,0 +1,502 @@
1
+ import { t as e } from "./resolve-Dc48n2Jo.js";
2
+ import { J as t, N as n, Q as r, W as i, X as a, Y as o, Z as s, g as c, n as l, r as u, t as d, tt as f, x as p } from "./icons-DTaPp44c.js";
3
+ import { A as m, E as h, M as g, N as _, O as v, T as y, a as b, c as x, d as S, f as C, h as w, i as T, j as ee, k as E, l as D, m as O, n as k, o as A, p as j, r as M, s as N, u as P, w as F } from "./mount-CMm0qSYk.js";
4
+ // node_modules/lucide/dist/esm/icons/armchair.mjs
5
+ var I = [
6
+ ["path", { d: "M19 9V6a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2v3" }],
7
+ ["path", { d: "M3 16a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-5a2 2 0 0 0-4 0v1.5a.5.5 0 0 1-.5.5h-9a.5.5 0 0 1-.5-.5V11a2 2 0 0 0-4 0z" }],
8
+ ["path", { d: "M5 18v2" }],
9
+ ["path", { d: "M19 18v2" }]
10
+ ], L = [
11
+ ["path", { d: "m16 17 5-5-5-5" }],
12
+ ["path", { d: "M21 12H9" }],
13
+ ["path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" }]
14
+ ], R = {
15
+ rank: 2,
16
+ suit: "spades"
17
+ }, z = (e, t = {}) => k(e ?? R, {
18
+ hidden: !e,
19
+ ...t
20
+ }), B = (e, t, n) => {
21
+ let r = e * Math.PI / 180;
22
+ return `left: ${50 + 50 * t * Math.cos(r)}%; top: ${100 * n * Math.sin(r)}%`;
23
+ };
24
+ function V(e, t, { cards: n, chips: i = () => r, outcome: a, sit: o, stand: s }) {
25
+ let c = (e) => 160 - e * 140 / Math.max(1, t.seats.length - 1);
26
+ return f`${t.seats.map((l, u) => {
27
+ if (!l) return f`<button
28
+ class="lk-seat is-free"
29
+ style=${B(c(u), 1, 1)}
30
+ ?disabled=${!o}
31
+ aria-label=${e.t("cards.sit")}
32
+ data-tip=${e.t("cards.sit")}
33
+ @click=${() => o?.(u)}
34
+ >
35
+ ${d(I)}
36
+ </button>`;
37
+ let p = u === t.you, m = a(l), h = n(l, p), g = i(l, p);
38
+ return f`
39
+ <div class="lk-seat ${p ? "is-mine" : "is-taken"} ${l.ready || l.playing ? "is-in" : ""} ${m ? `is-${m}` : ""}" style=${B(c(u), 1, 1)}>
40
+ ${l.avatar ? f`<img src=${l.avatar} alt="" />` : T}
41
+ <b>${l.name || e.t(p ? "cards.you" : "cards.player")}</b>
42
+ ${p && s ? f`<button class="lk-seat-leave ${u < (t.seats.length - 1) / 2 ? "is-left" : ""}" aria-label=${e.t("cards.stand")} data-tip=${e.t("cards.stand")} @click=${s}>${d(L)}</button>` : r}
43
+ </div>
44
+ ${g === r ? r : f`<div class="lk-seat-play lk-seat-bet ${p ? "is-mine" : ""}" style=${B(c(u), .84, .86)}>${g}</div>`}
45
+ ${h === r ? r : f`<div class="lk-seat-play ${p ? "is-mine" : ""} ${l.folded ? "is-folded" : ""}" style=${g === r ? B(c(u), .76, .82) : B(c(u), .6, .66)}>
46
+ ${h}
47
+ </div>`}
48
+ `;
49
+ })}`;
50
+ }
51
+ var H = (e) => e === null ? null : Math.max(0, Math.ceil((e - Date.now()) / 1e3)), U = 3;
52
+ async function* W(e) {
53
+ let t = e.getReader(), n = new TextDecoder(), r = "";
54
+ for (;;) {
55
+ let { value: e, done: i } = await t.read();
56
+ if (i) return;
57
+ r += n.decode(e, { stream: !0 }).replace(/\r\n?/g, "\n");
58
+ for (let e = r.indexOf("\n\n"); e >= 0; e = r.indexOf("\n\n")) {
59
+ let t = r.slice(0, e).split("\n").filter((e) => e.startsWith("data:")).map((e) => e.slice(e.startsWith("data: ") ? 6 : 5)).join("\n");
60
+ r = r.slice(e + 2), t && (yield JSON.parse(t));
61
+ }
62
+ }
63
+ }
64
+ var te = (e, t) => new Promise((n) => {
65
+ let r = setTimeout(n, e);
66
+ t.addEventListener("abort", () => (clearTimeout(r), n()), { once: !0 });
67
+ }), ne = class {
68
+ constructor(e, t) {
69
+ this.server = e, this.game = t, this.memory = null, this.connections = /* @__PURE__ */ new Set();
70
+ }
71
+ get key() {
72
+ return `feeling-lucky:${this.server.url}:${this.game}`;
73
+ }
74
+ get token() {
75
+ try {
76
+ return localStorage.getItem(this.key);
77
+ } catch {
78
+ return this.memory;
79
+ }
80
+ }
81
+ set token(e) {
82
+ this.memory = e;
83
+ try {
84
+ e ? localStorage.setItem(this.key, e) : localStorage.removeItem(this.key);
85
+ } catch {}
86
+ }
87
+ async request(t, n = {}) {
88
+ let r = {
89
+ "Content-Type": "application/json",
90
+ ...this.server.headers ? await e(this.server.headers) : {},
91
+ ...n.headers
92
+ };
93
+ return fetch(`${this.server.url.replace(/\/$/, "")}/${this.game}${t}`, {
94
+ ...n,
95
+ headers: r
96
+ });
97
+ }
98
+ reconnect() {
99
+ this.connections.forEach((e) => e.abort());
100
+ }
101
+ async listen(e, t) {
102
+ let n = (e) => e.key === this.key && this.reconnect();
103
+ addEventListener("storage", n);
104
+ try {
105
+ for (let n = 0; !t.aborted; await te(1e3 * n, t)) {
106
+ let r = new AbortController();
107
+ this.connections.add(r);
108
+ try {
109
+ let i = this.token, a = await this.request("", {
110
+ headers: i ? { "X-Seat-Token": i } : {},
111
+ signal: AbortSignal.any([t, r.signal])
112
+ });
113
+ if (a.status === 404 && i) {
114
+ this.token = null;
115
+ continue;
116
+ }
117
+ if (!a.ok || !a.body) throw Error(`feeling-lucky: the ${this.game} table did not answer (${a.status})`);
118
+ n = 0;
119
+ for await (let t of W(a.body)) e(t);
120
+ } catch (e) {
121
+ if (t.aborted || r.signal.aborted) continue;
122
+ if (++n > U) throw e;
123
+ } finally {
124
+ this.connections.delete(r);
125
+ }
126
+ }
127
+ } finally {
128
+ removeEventListener("storage", n);
129
+ }
130
+ }
131
+ async sit(e, t) {
132
+ await this.leave();
133
+ let n = await this.request("/seats", {
134
+ method: "POST",
135
+ body: JSON.stringify({
136
+ seat: e,
137
+ name: t?.name ?? null,
138
+ avatar: t?.avatar ?? null
139
+ })
140
+ });
141
+ this.token = n.ok ? (await n.json()).token : null, this.reconnect();
142
+ }
143
+ async stand() {
144
+ await this.leave(), this.reconnect();
145
+ }
146
+ async leave() {
147
+ let e = this.token;
148
+ this.token = null, e && await this.request("/seats", {
149
+ method: "DELETE",
150
+ headers: { "X-Seat-Token": e }
151
+ }).catch(() => void 0);
152
+ }
153
+ async act(e, t = {}) {
154
+ let n = this.token;
155
+ return n ? (await this.request("/actions", {
156
+ method: "POST",
157
+ headers: { "X-Seat-Token": n },
158
+ body: JSON.stringify({
159
+ action: e,
160
+ ...t
161
+ })
162
+ })).ok : !1;
163
+ }
164
+ }, G = /* @__PURE__ */ new Map();
165
+ function re(e, t) {
166
+ let n = `${e.url} ${t}`, r = G.get(n) ?? new ne(e, t);
167
+ return G.set(n, r), r.server = e, r;
168
+ }
169
+ // src/multiplayer/shared.ts
170
+ var K = (e) => e.dealer.length + e.seats.reduce((e, t) => e + (t?.hands.reduce((e, t) => e + t.cards.length, 0) ?? 0), 0), q = (e) => [
171
+ ...e.dealer,
172
+ ...e.board,
173
+ ...e.seats.flatMap((e) => e?.hands.flatMap((e) => e.cards) ?? [])
174
+ ].filter(Boolean).length, J = class extends l {
175
+ constructor() {
176
+ super(), this.options = {}, this.view = null, this.offline = !1, this.clearing = !1, this.stop = new AbortController(), this.next = null, this.ticker = 0, this.finished = -1, this.sit = (e) => {
177
+ this.canSit && this.table.sit(e, this.room.player);
178
+ }, this.stand = () => {
179
+ this.canStand && this.table.stand();
180
+ }, this.watch(p);
181
+ }
182
+ get mine() {
183
+ return this.view?.you == null ? null : this.view.seats[this.view.you] ?? null;
184
+ }
185
+ get canSit() {
186
+ return !this.mine || this.view?.phase === "betting" && !this.mine.ready;
187
+ }
188
+ get canStand() {
189
+ return !!this.mine && this.view?.phase === "betting" && !this.mine.ready;
190
+ }
191
+ connectedCallback() {
192
+ super.connectedCallback(), this.table = re(this.room.multiplayer, this.game), this.stop = new AbortController(), this.table.listen((e) => this.receive(e), this.stop.signal).catch(() => this.offline = !0), this.ticker = window.setInterval(() => this.view?.deadline && this.requestUpdate(), 250);
193
+ }
194
+ disconnectedCallback() {
195
+ super.disconnectedCallback(), this.stop.abort(), clearInterval(this.ticker);
196
+ }
197
+ act(e, t) {
198
+ this.table.act(e, t);
199
+ }
200
+ receive(e) {
201
+ this.clearing ? this.next = e : this.view?.phase === "done" && e.phase === "betting" ? (this.clearing = !0, this.next = e, b.play("whoosh", .4), this.later(() => {
202
+ this.clearing = !1, this.next && this.show(this.next), this.next = null;
203
+ }, D() ? 0 : 650)) : this.show(e);
204
+ }
205
+ show(e) {
206
+ let t = this.view;
207
+ this.view = e, t && e.phase === "dealing" && t.phase === "betting" && b.play("whoosh", .6), t && K(e) > K(t) ? b.play("tick", 1.25) : t && q(e) > q(t) && b.play("tick", 1.1), this.betting(t, e);
208
+ let n = this.mine;
209
+ if (!n?.result || this.finished === e.round) return;
210
+ if (this.finished = e.round, !n.tier || n.tier === "none") {
211
+ b.play("stop", .7);
212
+ return;
213
+ }
214
+ let r = this.outcome(n);
215
+ b.play(r.tier === "jackpot" ? "jackpot" : "win");
216
+ let i = this.felt?.getBoundingClientRect();
217
+ i && !D() && x.burst(i.left + i.width / 2, i.top + i.height * .55, {
218
+ count: 50,
219
+ type: "spark",
220
+ speed: 640,
221
+ life: .8,
222
+ gravity: 300,
223
+ colors: N
224
+ }), this.later(() => this.room.finish(r), D() ? 300 : 1700);
225
+ }
226
+ betting(e, t) {}
227
+ };
228
+ u([a({ attribute: !1 })], J.prototype, "options", void 0), u([o()], J.prototype, "view", void 0), u([o()], J.prototype, "offline", void 0), u([o()], J.prototype, "clearing", void 0), u([t(".lk-cards")], J.prototype, "felt", void 0);
229
+ // src/multiplayer/blackjack.ts
230
+ var Y = 5, ie = [
231
+ "win",
232
+ "dealerBust",
233
+ "natural",
234
+ "spades"
235
+ ], X = (e) => O(e.filter((e) => !!e)).total, Z = class extends J {
236
+ constructor(...e) {
237
+ super(...e), this.game = "blackjack", this.chosen = "", this.chips = [], this.history = [], this.lastBet = null;
238
+ }
239
+ willUpdate() {
240
+ this.room.prizeIds.includes(this.chosen) || (this.chosen = this.room.prizeIds[0]);
241
+ }
242
+ betting(e, t) {
243
+ t.phase === "betting" && e?.phase !== "betting" && (this.chips = [], this.history = []);
244
+ }
245
+ get open() {
246
+ let e = this.mine;
247
+ return this.view?.phase === "betting" && !!e && !e.ready;
248
+ }
249
+ get turn() {
250
+ let e = this.mine;
251
+ return this.view?.phase === "acting" && !!e?.playing && !e.decided;
252
+ }
253
+ get hand() {
254
+ return this.mine?.hands[this.mine.active];
255
+ }
256
+ get theirs() {
257
+ return X(this.view?.dealer ?? []);
258
+ }
259
+ beats(e) {
260
+ return X(e) <= 21 && (this.theirs > 21 || this.theirs < X(e));
261
+ }
262
+ bet() {
263
+ !this.open || this.chips.length >= Y || (this.history = [...this.history, [...this.chips]], this.chips = [...this.chips, this.chosen]);
264
+ }
265
+ undo() {
266
+ let e = this.history.at(-1);
267
+ e && (this.history = this.history.slice(0, -1), this.chips = e);
268
+ }
269
+ rebet() {
270
+ this.lastBet && !this.chips.length && (this.history = [...this.history, []], this.chips = this.lastBet.filter((e) => this.room.prizeIds.includes(e)));
271
+ }
272
+ clearChips() {
273
+ this.history = [...this.history, [...this.chips]], this.chips = [];
274
+ }
275
+ deal() {
276
+ this.open && this.chips.length && (this.lastBet = [...this.chips], this.act("bet", {
277
+ prize: this.chips[0],
278
+ chips: this.chips.length
279
+ }));
280
+ }
281
+ outcome(e) {
282
+ let t = e.prize && this.room.prizeIds.includes(e.prize) ? e.prize : this.room.prizeIds[0], r = e.tier;
283
+ return {
284
+ game: "blackjack",
285
+ tier: r,
286
+ prizeId: t,
287
+ award: n(this.room.prize(t), r),
288
+ detail: { key: `detail.blackjack.${e.result}` }
289
+ };
290
+ }
291
+ hands(e, t, n = -1) {
292
+ return e.hands.map((e, i) => f`
293
+ <div class="lk-split ${i === n ? "is-active" : ""}">
294
+ <div class="lk-hand">${e.cards.map((n) => z(n, { lit: t(e.cards) }))}</div>
295
+ ${e.cards.length ? f`<span class="lk-hand-total ${X(e.cards) > 21 ? "is-bust" : ""}"
296
+ >${X(e.cards)}${e.stacks > 1 ? f`<small>×2</small>` : r}</span
297
+ >` : r}
298
+ </div>
299
+ `);
300
+ }
301
+ chipsOf(e, t, n) {
302
+ let { room: r } = this;
303
+ return Array.from({ length: t }, (i, a) => e.map((e, i) => f`<i class="lk-bet-chip ${n ? "is-winning" : ""}" style="--lk-chip: ${r.color(e)}; --n: ${i}; --stack: ${a - (t - 1) / 2}"><img src=${r.icon(e)} alt="" /></i>`));
304
+ }
305
+ render() {
306
+ if (this.offline) return f`<fl-blackjack .options=${this.options}></fl-blackjack>`;
307
+ let { room: e, view: t, mine: n } = this, i = t?.phase ?? "betting", a = n?.result ?? null, o = !!a && ie.includes(a) && !!n?.tier && n.tier !== "none", s = i === "dealing" || i === "dealer", c = n?.ready || n?.playing ? Array.from({ length: n.chips }, () => n.prize ?? e.prizeIds[0]) : this.chips, l = n?.hands.reduce((e, t) => e + t.stacks, 0) || 1, u = H(t?.deadline ?? null), b = t ? n ? !n.playing && i !== "betting" ? this.t("cards.nextHand") : i === "betting" && u !== null ? this.t("cards.dealingIn", { seconds: u }) : this.turn && u !== null ? this.t("cards.playIn", { seconds: u }) : null : this.t("cards.chooseSeat") : null, x = f`
308
+ <span class="lk-hand-name">${this.t("cards.dealer")}${t?.dealer.length ? f`<b>${this.theirs}</b>` : r}</span>
309
+ <div class="lk-hand">${t?.dealer.map((e) => z(e)) ?? r}</div>
310
+ `, S = f`${a ? f`<p class="lk-cards-result ${o ? "is-won" : ""}">${this.t(`blackjack.result.${a}`)}</p>` : b ? f`<p class="lk-cards-status">${b}</p>` : r}`, w = f`
311
+ <button
312
+ class="lk-bet ${this.open && c.length < Y ? "is-open" : ""}"
313
+ ?disabled=${!this.open || c.length >= Y}
314
+ aria-label=${this.t("blackjack.bet", { prize: e.name(this.chosen) })}
315
+ @click=${this.bet}
316
+ >
317
+ ${this.chipsOf(c, l, o)}
318
+ </button>
319
+ `, T = t ? V(e, t, {
320
+ cards: (e, t) => e.playing ? f`${this.hands(e, (e) => t && o && (a === "natural" || a === "spades" || this.beats(e)), t && e.hands.length > 1 && this.turn ? e.active : -1)}` : r,
321
+ chips: (t, n) => n ? w : t.ready || t.playing ? f`<span class="lk-bet">${this.chipsOf(Array.from({ length: t.chips }, () => t.prize ?? e.prizeIds[0]), t.hands.reduce((e, t) => e + t.stacks, 0) || 1, !1)}</span>` : r,
322
+ outcome: (e) => e.result ? e.tier && e.tier !== "none" ? "won" : "lost" : null,
323
+ sit: this.canSit ? this.sit : null,
324
+ stand: this.canStand ? this.stand : null
325
+ }) : void 0;
326
+ return A(e.t, {
327
+ state: o ? "won" : s ? "spinning" : "idle",
328
+ rules: this.t("games.blackjack.rules"),
329
+ multiplier: t?.boost ?? 1,
330
+ dealer: !0
331
+ }, f`
332
+ <div class="lk-cards lk-cards--blackjack lk-cards--shared ${this.clearing ? "is-clearing" : ""}">
333
+ ${M(e, this.t("blackjack.print"), {
334
+ dealer: x,
335
+ centre: S,
336
+ player: f``,
337
+ seats: T
338
+ }, {
339
+ on: p.value,
340
+ dealing: s
341
+ })}
342
+ <div class="lk-rl-rack lk-cards-rack">
343
+ <fl-chips
344
+ .chosen=${this.chosen}
345
+ .disabled=${!this.open}
346
+ .locked=${c[0] ?? null}
347
+ .count=${{
348
+ used: c.length,
349
+ max: Y
350
+ }}
351
+ @choose=${(e) => this.chosen = e.detail}
352
+ ></fl-chips>
353
+ <div class="lk-rl-actions">
354
+ <div class="lk-rl-quick">
355
+ <button
356
+ class="lk-round"
357
+ aria-label=${this.t("roulette.undo")}
358
+ data-tip=${this.t("roulette.undo")}
359
+ ?disabled=${!this.history.length || !this.open}
360
+ @click=${this.undo}
361
+ >
362
+ ${d(F)}
363
+ </button>
364
+ <button
365
+ class="lk-round"
366
+ aria-label=${this.t("roulette.rebet")}
367
+ data-tip=${this.t("roulette.rebet")}
368
+ ?disabled=${!this.lastBet || !!this.chips.length || !this.open}
369
+ @click=${this.rebet}
370
+ >
371
+ ${d(v)}
372
+ </button>
373
+ <button
374
+ class="lk-round"
375
+ aria-label=${this.t("roulette.clear")}
376
+ data-tip=${this.t("roulette.clear")}
377
+ ?disabled=${!this.chips.length || !this.open}
378
+ @click=${this.clearChips}
379
+ >
380
+ ${d(y)}
381
+ </button>
382
+ </div>
383
+ ${i === "acting" && n?.playing ? f`
384
+ <button class="lk-btn lk-btn--primary lk-btn--lg" ?disabled=${!this.turn} @click=${() => this.act("hit")}>
385
+ ${d(g)}${this.t("blackjack.hit")}
386
+ </button>
387
+ <button class="lk-btn lk-btn--outline lk-btn--lg" ?disabled=${!this.turn} @click=${() => this.act("stand")}>
388
+ ${d(m)}${this.t("blackjack.stand")}
389
+ </button>
390
+ <button
391
+ class="lk-btn lk-btn--outline lk-btn--lg"
392
+ ?disabled=${!this.turn || this.hand?.cards.length !== 2}
393
+ @click=${() => this.act("double")}
394
+ >
395
+ ${d(_)}${this.t("blackjack.double")}
396
+ </button>
397
+ <button
398
+ class="lk-btn lk-btn--outline lk-btn--lg"
399
+ ?disabled=${!this.turn || n.hands.length !== 1 || !C(n.hands[0].cards.filter((e) => !!e))}
400
+ @click=${() => this.act("split")}
401
+ >
402
+ ${d(h)}${this.t("blackjack.split")}
403
+ </button>
404
+ ` : f`<button class="lk-btn lk-btn--primary lk-btn--lg" ?disabled=${!this.open || !this.chips.length} @click=${this.deal}>
405
+ ${d(E)}${this.t("cards.deal")}
406
+ </button>`}
407
+ </div>
408
+ </div>
409
+ </div>
410
+ `);
411
+ }
412
+ };
413
+ u([o()], Z.prototype, "chosen", void 0), u([o()], Z.prototype, "chips", void 0), u([o()], Z.prototype, "history", void 0), u([o()], Z.prototype, "lastBet", void 0), Z = u([s("fl-blackjack-shared")], Z);
414
+ // src/multiplayer/holdem.ts
415
+ var Q = (e) => e.every(Boolean) ? e : null, $ = class extends J {
416
+ constructor(...e) {
417
+ super(...e), this.game = "holdem";
418
+ }
419
+ handName(e) {
420
+ return this.t(`holdem.hands.${P[e]}`);
421
+ }
422
+ made(e) {
423
+ let t = this.view, n = Q(t?.board ?? []), r = Q(e), i = Q(t?.dealer ?? []);
424
+ return n?.length === 5 && r?.length && i?.length ? w(r, i, n) : null;
425
+ }
426
+ outcome(e) {
427
+ let t = c("holdem", this.room.prizeIds), r = e.tier, i = this.made(e.hands[0]?.cards ?? []);
428
+ return {
429
+ game: "holdem",
430
+ tier: r,
431
+ prizeId: t,
432
+ award: n(this.room.prize(t), r),
433
+ detail: {
434
+ key: "detail.holdem",
435
+ params: { hand: i ? this.handName(i.mine.category) : "" }
436
+ }
437
+ };
438
+ }
439
+ render() {
440
+ if (this.offline) return f`<fl-holdem .options=${this.options}></fl-holdem>`;
441
+ let { room: e, view: t, mine: n } = this, a = t?.phase ?? "betting", o = n?.hands[0]?.cards ?? [], s = n?.folded ? null : this.made(o), c = !!n?.tier && n.tier !== "none", l = a === "dealing" || a === "dealer", u = a === "acting" && !!n?.playing && !n.decided, m = H(t?.deadline ?? null), h = t ? n ? !n.playing && a !== "betting" ? this.t("cards.nextHand") : a === "betting" && m !== null ? this.t("cards.dealingIn", { seconds: m }) : u && m !== null ? this.t("cards.playIn", { seconds: m }) : null : this.t("cards.chooseSeat") : null, g = !s || this.clearing ? [] : s.lost ? j(s.theirs) : c ? j(s.mine) : [...j(s.mine), ...j(s.theirs)], _ = (e) => !!e && g.some((t) => t.rank === e.rank && t.suit === e.suit), v = f`
442
+ <span class="lk-hand-name">${this.t("cards.dealer")}${s ? f`<b>${this.handName(s.theirs.category)}</b>` : r}</span>
443
+ <div class="lk-hand">${t?.dealer.map((e) => z(e, { lit: _(e) })) ?? r}</div>
444
+ `, y = n?.result === "folded" ? this.t("holdem.result.folded") : s && n?.result ? c ? this.t("holdem.result.won", { hand: this.handName(s.mine.category) }) : s.lost ? this.t("holdem.result.lost", { hand: this.handName(s.theirs.category) }) : this.t("holdem.result.split") : null, b = f`
445
+ <div class="lk-board">
446
+ ${(t?.board.length ? t.board : Array.from({ length: 5 }, () => null)).map((e) => e ? z(e, { lit: _(e) }) : f`<i class="lk-board-slot"></i>`)}
447
+ </div>
448
+ ${y ? f`<p class="lk-cards-result ${c ? "is-won" : ""}">${y}</p>` : h ? f`<p class="lk-cards-status">${h}</p>` : r}
449
+ `, x = f`
450
+ <div class="lk-hand">${o.map((e) => z(e, { lit: _(e) }))}</div>
451
+ ${s ? f`<span class="lk-hand-total is-name">${this.handName(s.mine.category)}</span>` : r}
452
+ `, C = t ? V(e, t, {
453
+ cards: (e, n) => {
454
+ if (!e.playing) return r;
455
+ if (n) return x;
456
+ let i = Q(e.hands[0]?.cards ?? []), a = Q(t.board);
457
+ return f`
458
+ <div class="lk-hand">${e.hands[0]?.cards.map((e) => z(e)) ?? r}</div>
459
+ ${i?.length && a?.length === 5 && !e.folded ? f`<span class="lk-hand-total is-name">${this.handName(S([...i, ...a]).category)}</span>` : r}
460
+ `;
461
+ },
462
+ outcome: (e) => e.result ? e.tier && e.tier !== "none" ? "won" : "lost" : null,
463
+ sit: this.canSit ? this.sit : null,
464
+ stand: this.canStand ? this.stand : null
465
+ }) : void 0;
466
+ return A(e.t, {
467
+ state: c && n?.result ? "won" : l ? "spinning" : "idle",
468
+ rules: this.t("games.holdem.rules"),
469
+ multiplier: t?.boost ?? 1,
470
+ dealer: !0
471
+ }, f`
472
+ <div class="lk-cards lk-cards--holdem lk-cards--shared ${this.clearing ? "is-clearing" : ""}">
473
+ ${M(e, this.t("holdem.print"), {
474
+ dealer: v,
475
+ centre: b,
476
+ player: f``,
477
+ seats: C
478
+ }, {
479
+ on: p.value,
480
+ dealing: l
481
+ })}
482
+ <div class="lk-controls lk-cards-controls">
483
+ ${a === "acting" && n?.playing ? f`
484
+ <button class="lk-btn lk-btn--primary lk-btn--lg" ?disabled=${!u} @click=${() => this.act("call")}>
485
+ ${d(ee)}${this.t("holdem.call")}
486
+ </button>
487
+ <button class="lk-btn lk-btn--outline lk-btn--lg" ?disabled=${!u} @click=${() => this.act("fold")}>
488
+ ${d(i)}${this.t("holdem.fold")}
489
+ </button>
490
+ ` : f`<button
491
+ class="lk-btn lk-btn--primary lk-btn--lg"
492
+ ?disabled=${a !== "betting" || !n || n.ready}
493
+ @click=${() => this.act("deal")}
494
+ >
495
+ ${d(E)}${this.t("cards.deal")}
496
+ </button>`}
497
+ </div>
498
+ </div>
499
+ `);
500
+ }
501
+ };
502
+ $ = u([s("fl-holdem-shared")], $);