@hellacardgames/speed 0.5.3 → 0.7.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 (39) hide show
  1. package/dist/client/index.cjs.map +1 -1
  2. package/dist/client/index.d.cts +2 -2
  3. package/dist/client/index.d.cts.map +1 -1
  4. package/dist/client/index.d.mts +2 -2
  5. package/dist/client/index.d.mts.map +1 -1
  6. package/dist/client/index.mjs.map +1 -1
  7. package/dist/index-BRtLpRz1.d.mts +125 -0
  8. package/dist/index-BRtLpRz1.d.mts.map +1 -0
  9. package/dist/index-BvZyhFek.d.cts +125 -0
  10. package/dist/index-BvZyhFek.d.cts.map +1 -0
  11. package/dist/{index-BilCO_4a.d.cts → index-xmcja9Bl.d.cts} +91 -60
  12. package/dist/index-xmcja9Bl.d.cts.map +1 -0
  13. package/dist/{index-BilCO_4a.d.mts → index-xmcja9Bl.d.mts} +91 -60
  14. package/dist/index-xmcja9Bl.d.mts.map +1 -0
  15. package/dist/manager/index.cjs +2 -12
  16. package/dist/manager/index.d.cts +2 -2
  17. package/dist/manager/index.d.mts +2 -2
  18. package/dist/manager/index.mjs +2 -2
  19. package/dist/manager-8x5AFyzq.mjs +790 -0
  20. package/dist/manager-8x5AFyzq.mjs.map +1 -0
  21. package/dist/manager-BxLMVu_o.cjs +795 -0
  22. package/dist/manager-BxLMVu_o.cjs.map +1 -0
  23. package/dist/server/index.cjs +141 -157
  24. package/dist/server/index.cjs.map +1 -1
  25. package/dist/server/index.d.cts +3 -3
  26. package/dist/server/index.d.mts +3 -3
  27. package/dist/server/index.mjs +141 -157
  28. package/dist/server/index.mjs.map +1 -1
  29. package/package.json +2 -2
  30. package/dist/index-BilCO_4a.d.cts.map +0 -1
  31. package/dist/index-BilCO_4a.d.mts.map +0 -1
  32. package/dist/index-DSPZZlhq.d.cts +0 -143
  33. package/dist/index-DSPZZlhq.d.cts.map +0 -1
  34. package/dist/index-S-oO1z9X.d.mts +0 -143
  35. package/dist/index-S-oO1z9X.d.mts.map +0 -1
  36. package/dist/manager-CPmezdJa.mjs +0 -834
  37. package/dist/manager-CPmezdJa.mjs.map +0 -1
  38. package/dist/manager-DErQ_XUq.cjs +0 -899
  39. package/dist/manager-DErQ_XUq.cjs.map +0 -1
@@ -0,0 +1,790 @@
1
+ import { ManagerBase } from "@hellacardgames/lib";
2
+ //#region src/manager/constants.ts
3
+ const EXPIRY_EXTENSION_MS = 3e5;
4
+ const CAN_PLAY_AT_DELAY_MS = 3e3;
5
+ const CARDS = [
6
+ {
7
+ id: crypto.randomUUID(),
8
+ rank: 2,
9
+ suite: "clubs"
10
+ },
11
+ {
12
+ id: crypto.randomUUID(),
13
+ rank: 3,
14
+ suite: "clubs"
15
+ },
16
+ {
17
+ id: crypto.randomUUID(),
18
+ rank: 4,
19
+ suite: "clubs"
20
+ },
21
+ {
22
+ id: crypto.randomUUID(),
23
+ rank: 5,
24
+ suite: "clubs"
25
+ },
26
+ {
27
+ id: crypto.randomUUID(),
28
+ rank: 6,
29
+ suite: "clubs"
30
+ },
31
+ {
32
+ id: crypto.randomUUID(),
33
+ rank: 7,
34
+ suite: "clubs"
35
+ },
36
+ {
37
+ id: crypto.randomUUID(),
38
+ rank: 8,
39
+ suite: "clubs"
40
+ },
41
+ {
42
+ id: crypto.randomUUID(),
43
+ rank: 9,
44
+ suite: "clubs"
45
+ },
46
+ {
47
+ id: crypto.randomUUID(),
48
+ rank: 10,
49
+ suite: "clubs"
50
+ },
51
+ {
52
+ id: crypto.randomUUID(),
53
+ rank: 11,
54
+ suite: "clubs"
55
+ },
56
+ {
57
+ id: crypto.randomUUID(),
58
+ rank: 12,
59
+ suite: "clubs"
60
+ },
61
+ {
62
+ id: crypto.randomUUID(),
63
+ rank: 13,
64
+ suite: "clubs"
65
+ },
66
+ {
67
+ id: crypto.randomUUID(),
68
+ rank: 14,
69
+ suite: "clubs"
70
+ },
71
+ {
72
+ id: crypto.randomUUID(),
73
+ rank: 2,
74
+ suite: "diamonds"
75
+ },
76
+ {
77
+ id: crypto.randomUUID(),
78
+ rank: 3,
79
+ suite: "diamonds"
80
+ },
81
+ {
82
+ id: crypto.randomUUID(),
83
+ rank: 4,
84
+ suite: "diamonds"
85
+ },
86
+ {
87
+ id: crypto.randomUUID(),
88
+ rank: 5,
89
+ suite: "diamonds"
90
+ },
91
+ {
92
+ id: crypto.randomUUID(),
93
+ rank: 6,
94
+ suite: "diamonds"
95
+ },
96
+ {
97
+ id: crypto.randomUUID(),
98
+ rank: 7,
99
+ suite: "diamonds"
100
+ },
101
+ {
102
+ id: crypto.randomUUID(),
103
+ rank: 8,
104
+ suite: "diamonds"
105
+ },
106
+ {
107
+ id: crypto.randomUUID(),
108
+ rank: 9,
109
+ suite: "diamonds"
110
+ },
111
+ {
112
+ id: crypto.randomUUID(),
113
+ rank: 10,
114
+ suite: "diamonds"
115
+ },
116
+ {
117
+ id: crypto.randomUUID(),
118
+ rank: 11,
119
+ suite: "diamonds"
120
+ },
121
+ {
122
+ id: crypto.randomUUID(),
123
+ rank: 12,
124
+ suite: "diamonds"
125
+ },
126
+ {
127
+ id: crypto.randomUUID(),
128
+ rank: 13,
129
+ suite: "diamonds"
130
+ },
131
+ {
132
+ id: crypto.randomUUID(),
133
+ rank: 14,
134
+ suite: "diamonds"
135
+ },
136
+ {
137
+ id: crypto.randomUUID(),
138
+ rank: 2,
139
+ suite: "hearts"
140
+ },
141
+ {
142
+ id: crypto.randomUUID(),
143
+ rank: 3,
144
+ suite: "hearts"
145
+ },
146
+ {
147
+ id: crypto.randomUUID(),
148
+ rank: 4,
149
+ suite: "hearts"
150
+ },
151
+ {
152
+ id: crypto.randomUUID(),
153
+ rank: 5,
154
+ suite: "hearts"
155
+ },
156
+ {
157
+ id: crypto.randomUUID(),
158
+ rank: 6,
159
+ suite: "hearts"
160
+ },
161
+ {
162
+ id: crypto.randomUUID(),
163
+ rank: 7,
164
+ suite: "hearts"
165
+ },
166
+ {
167
+ id: crypto.randomUUID(),
168
+ rank: 8,
169
+ suite: "hearts"
170
+ },
171
+ {
172
+ id: crypto.randomUUID(),
173
+ rank: 9,
174
+ suite: "hearts"
175
+ },
176
+ {
177
+ id: crypto.randomUUID(),
178
+ rank: 10,
179
+ suite: "hearts"
180
+ },
181
+ {
182
+ id: crypto.randomUUID(),
183
+ rank: 11,
184
+ suite: "hearts"
185
+ },
186
+ {
187
+ id: crypto.randomUUID(),
188
+ rank: 12,
189
+ suite: "hearts"
190
+ },
191
+ {
192
+ id: crypto.randomUUID(),
193
+ rank: 13,
194
+ suite: "hearts"
195
+ },
196
+ {
197
+ id: crypto.randomUUID(),
198
+ rank: 14,
199
+ suite: "hearts"
200
+ },
201
+ {
202
+ id: crypto.randomUUID(),
203
+ rank: 2,
204
+ suite: "spades"
205
+ },
206
+ {
207
+ id: crypto.randomUUID(),
208
+ rank: 3,
209
+ suite: "spades"
210
+ },
211
+ {
212
+ id: crypto.randomUUID(),
213
+ rank: 4,
214
+ suite: "spades"
215
+ },
216
+ {
217
+ id: crypto.randomUUID(),
218
+ rank: 5,
219
+ suite: "spades"
220
+ },
221
+ {
222
+ id: crypto.randomUUID(),
223
+ rank: 6,
224
+ suite: "spades"
225
+ },
226
+ {
227
+ id: crypto.randomUUID(),
228
+ rank: 7,
229
+ suite: "spades"
230
+ },
231
+ {
232
+ id: crypto.randomUUID(),
233
+ rank: 8,
234
+ suite: "spades"
235
+ },
236
+ {
237
+ id: crypto.randomUUID(),
238
+ rank: 9,
239
+ suite: "spades"
240
+ },
241
+ {
242
+ id: crypto.randomUUID(),
243
+ rank: 10,
244
+ suite: "spades"
245
+ },
246
+ {
247
+ id: crypto.randomUUID(),
248
+ rank: 11,
249
+ suite: "spades"
250
+ },
251
+ {
252
+ id: crypto.randomUUID(),
253
+ rank: 12,
254
+ suite: "spades"
255
+ },
256
+ {
257
+ id: crypto.randomUUID(),
258
+ rank: 13,
259
+ suite: "spades"
260
+ },
261
+ {
262
+ id: crypto.randomUUID(),
263
+ rank: 14,
264
+ suite: "spades"
265
+ }
266
+ ];
267
+ //#endregion
268
+ //#region src/lib/emitEvent.ts
269
+ function emitEvent(game, data) {
270
+ const event = {
271
+ ...data,
272
+ id: crypto.randomUUID()
273
+ };
274
+ for (const p of game.players) p.events.push(event);
275
+ }
276
+ //#endregion
277
+ //#region src/lib/emitEventToPlayer.ts
278
+ function emitEventToPlayer(player, data) {
279
+ player.events.push({
280
+ ...data,
281
+ id: crypto.randomUUID()
282
+ });
283
+ }
284
+ //#endregion
285
+ //#region src/manager/lib/isCardPlayable.ts
286
+ function isCardPlayable(card, targetPile) {
287
+ const targetCard = targetPile[targetPile.length - 1];
288
+ return Math.abs(card.rank - targetCard.rank) % 11 === 1;
289
+ }
290
+ //#endregion
291
+ //#region src/manager/lib/hasPlayableCard.ts
292
+ function hasPlayableCard(player, game) {
293
+ const otherPlayer = game.players.find((p) => p !== player);
294
+ const targetPile1 = player.centerPile;
295
+ const targetPile2 = otherPlayer.centerPile;
296
+ for (const card of player.hand) if (isCardPlayable(card, targetPile1) || isCardPlayable(card, targetPile2)) return true;
297
+ return false;
298
+ }
299
+ //#endregion
300
+ //#region src/lib/shuffleCards.ts
301
+ function shuffleCards(cards) {
302
+ for (let i = cards.length - 1; i > 0; i--) {
303
+ const j = Math.floor(Math.random() * (i + 1));
304
+ [cards[i], cards[j]] = [cards[j], cards[i]];
305
+ }
306
+ }
307
+ //#endregion
308
+ //#region src/manager/Manager.ts
309
+ var Manager = class extends ManagerBase {
310
+ createGame(userId, username) {
311
+ if (this.games.size === this.maxGames) return {
312
+ success: false,
313
+ error: "maxGamesReached"
314
+ };
315
+ const player = {
316
+ id: crypto.randomUUID(),
317
+ userId,
318
+ username,
319
+ events: [],
320
+ hand: [],
321
+ drawPile: [],
322
+ sidePile: [],
323
+ centerPile: [],
324
+ hasNoPlayableCards: false
325
+ };
326
+ const createdAt = Date.now();
327
+ const game = {
328
+ status: "open",
329
+ id: crypto.randomUUID(),
330
+ createdAt,
331
+ expiresAt: createdAt + EXPIRY_EXTENSION_MS,
332
+ chatMessages: [],
333
+ players: [player]
334
+ };
335
+ this.games.set(game.id, game);
336
+ return {
337
+ success: true,
338
+ gameId: game.id,
339
+ playerId: player.id
340
+ };
341
+ }
342
+ drawCard(gameId, playerId) {
343
+ const game = this.games.get(gameId);
344
+ if (!game) return {
345
+ success: false,
346
+ error: "gameNotFound"
347
+ };
348
+ const player = game.players.find((p) => p.id === playerId);
349
+ if (!player) return {
350
+ success: false,
351
+ error: "playerNotFound"
352
+ };
353
+ if (game.status !== "started") return {
354
+ success: false,
355
+ error: "invalidStatus"
356
+ };
357
+ if (Date.now() < game.canPlayAt) return {
358
+ success: false,
359
+ error: "canPlayAtNotReached"
360
+ };
361
+ if (player.hand.length >= 5) return {
362
+ success: false,
363
+ error: "handFull"
364
+ };
365
+ if (player.drawPile.length === 0) return {
366
+ success: false,
367
+ error: "drawPileEmpty"
368
+ };
369
+ game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;
370
+ emitEvent(game, {
371
+ type: "expirationUpdated",
372
+ expiresAt: game.expiresAt
373
+ });
374
+ const card = player.drawPile.pop();
375
+ player.hand.push(card);
376
+ emitEventToPlayer(player, {
377
+ type: "drewCard",
378
+ card
379
+ });
380
+ emitEvent(game, {
381
+ type: "playerDrewCard",
382
+ username: player.username
383
+ });
384
+ return { success: true };
385
+ }
386
+ getClientStateAndClearEvents(gameId, playerId) {
387
+ const game = this.games.get(gameId);
388
+ if (!game) return {
389
+ success: false,
390
+ error: "gameNotFound"
391
+ };
392
+ const player = game.players.find((p) => p.id === playerId);
393
+ if (!player) return {
394
+ success: false,
395
+ error: "playerNotFound"
396
+ };
397
+ const state = {
398
+ status: game.status,
399
+ gameId,
400
+ playerId,
401
+ username: player.username,
402
+ players: game.players.map((p) => ({
403
+ username: p.username,
404
+ handSize: p.hand.length,
405
+ drawPileSize: p.drawPile.length,
406
+ sidePileSize: p.sidePile.length,
407
+ centerPileTopCard: p.centerPile.length ? p.centerPile[p.centerPile.length - 1] : null
408
+ })),
409
+ expiresAt: game.expiresAt,
410
+ chatMessages: game.chatMessages,
411
+ hand: player.hand,
412
+ canPlayAt: game.status === "started" ? game.canPlayAt : null
413
+ };
414
+ player.events.length = 0;
415
+ return {
416
+ success: true,
417
+ state
418
+ };
419
+ }
420
+ getEventsAndClearAcknowledged(gameId, playerId, lastReadId) {
421
+ const game = this.games.get(gameId);
422
+ if (!game) return {
423
+ success: false,
424
+ error: "gameNotFound"
425
+ };
426
+ const player = game.players.find((p) => p.id === playerId);
427
+ if (!player) return {
428
+ success: false,
429
+ error: "playerNotFound"
430
+ };
431
+ const lastReadEventIndex = player.events.findIndex((e) => e.id === lastReadId);
432
+ player.events.splice(0, lastReadEventIndex + 1);
433
+ return {
434
+ success: true,
435
+ events: player.events
436
+ };
437
+ }
438
+ getJoinableGames() {
439
+ return { games: Array.from(this.games.values()).filter((g) => g.status === "open" && g.players.length < 2).map((g) => ({
440
+ id: g.id,
441
+ numPlayers: g.players.length
442
+ })) };
443
+ }
444
+ joinGame(gameId, userId, username) {
445
+ const game = this.games.get(gameId);
446
+ if (!game) return {
447
+ success: false,
448
+ error: "gameNotFound"
449
+ };
450
+ if (game.status !== "open") return {
451
+ success: false,
452
+ error: "invalidStatus"
453
+ };
454
+ if (game.players.length === 2) return {
455
+ success: false,
456
+ error: "maxPlayersReached"
457
+ };
458
+ if (game.players.find((p) => p.userId === userId)) return {
459
+ success: false,
460
+ error: "alreadyInGame"
461
+ };
462
+ const player = {
463
+ id: crypto.randomUUID(),
464
+ userId,
465
+ username,
466
+ events: [],
467
+ hand: [],
468
+ drawPile: [],
469
+ sidePile: [],
470
+ centerPile: [],
471
+ hasNoPlayableCards: false
472
+ };
473
+ game.players.push(player);
474
+ emitEvent(game, {
475
+ type: "playerJoined",
476
+ username
477
+ });
478
+ return {
479
+ success: true,
480
+ playerId: player.id
481
+ };
482
+ }
483
+ leaveGame(gameId, playerId) {
484
+ const game = this.games.get(gameId);
485
+ if (!game) return {
486
+ success: false,
487
+ error: "gameNotFound"
488
+ };
489
+ const playerIndex = game.players.findIndex((p) => p.id === playerId);
490
+ if (playerIndex === -1) return {
491
+ success: false,
492
+ error: "playerNotFound"
493
+ };
494
+ const player = game.players[playerIndex];
495
+ emitEvent(game, {
496
+ type: "playerLeft",
497
+ username: player.username
498
+ });
499
+ game.players.splice(playerIndex, 1);
500
+ if (game.status === "started" && game.players.length < 2) {
501
+ const forfeitedGame = {
502
+ ...game,
503
+ status: "forfeited",
504
+ expiresAt: Date.now() + EXPIRY_EXTENSION_MS
505
+ };
506
+ this.games.set(game.id, forfeitedGame);
507
+ emitEvent(forfeitedGame, { type: "gameForfeited" });
508
+ emitEvent(forfeitedGame, {
509
+ type: "expirationUpdated",
510
+ expiresAt: forfeitedGame.expiresAt
511
+ });
512
+ }
513
+ if (game.players.length === 0) this.games.delete(game.id);
514
+ return { success: true };
515
+ }
516
+ playCard(gameId, playerId, cardId, isForOtherPlayerPile) {
517
+ const game = this.games.get(gameId);
518
+ if (!game) return {
519
+ success: false,
520
+ error: "gameNotFound"
521
+ };
522
+ const player = game.players.find((p) => p.id === playerId);
523
+ if (!player) return {
524
+ success: false,
525
+ error: "playerNotFound"
526
+ };
527
+ if (game.status !== "started") return {
528
+ success: false,
529
+ error: "invalidStatus"
530
+ };
531
+ if (Date.now() < game.canPlayAt) return {
532
+ success: false,
533
+ error: "canPlayAtNotReached"
534
+ };
535
+ const cardIndex = player.hand.findIndex((c) => c.id === cardId);
536
+ if (cardIndex === -1) return {
537
+ success: false,
538
+ error: "cardNotFound"
539
+ };
540
+ const otherPlayer = game.players.find((p) => p !== player);
541
+ const targetPile = isForOtherPlayerPile ? otherPlayer.centerPile : player.centerPile;
542
+ const card = player.hand[cardIndex];
543
+ if (!isCardPlayable(card, targetPile)) return {
544
+ success: false,
545
+ error: "cardNotPlayable"
546
+ };
547
+ game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;
548
+ emitEvent(game, {
549
+ type: "expirationUpdated",
550
+ expiresAt: game.expiresAt
551
+ });
552
+ player.hand.splice(cardIndex, 1);
553
+ targetPile.push(card);
554
+ emitEvent(game, {
555
+ type: "cardPlayed",
556
+ username: player.username,
557
+ card,
558
+ isForOtherPlayerPile
559
+ });
560
+ if (otherPlayer.hasNoPlayableCards && hasPlayableCard(otherPlayer, game)) otherPlayer.hasNoPlayableCards = false;
561
+ if (player.hand.length === 0 && player.drawPile.length === 0) {
562
+ emitEvent(game, { type: "gameCompleted" });
563
+ const completedGame = {
564
+ ...game,
565
+ status: "completed"
566
+ };
567
+ this.games.set(game.id, completedGame);
568
+ }
569
+ return { success: true };
570
+ }
571
+ reportNoPlayableCards(gameId, playerId) {
572
+ const game = this.games.get(gameId);
573
+ if (!game) return {
574
+ success: false,
575
+ error: "gameNotFound"
576
+ };
577
+ const player = game.players.find((p) => p.id === playerId);
578
+ if (!player) return {
579
+ success: false,
580
+ error: "playerNotFound"
581
+ };
582
+ if (game.status !== "started") return {
583
+ success: false,
584
+ error: "invalidStatus"
585
+ };
586
+ if (Date.now() < game.canPlayAt) return {
587
+ success: false,
588
+ error: "canPlayAtNotReached"
589
+ };
590
+ if (player.hasNoPlayableCards) return {
591
+ success: false,
592
+ error: "alreadyReported"
593
+ };
594
+ if (hasPlayableCard(player, game)) return {
595
+ success: false,
596
+ error: "hasPlayableCard"
597
+ };
598
+ if (player.drawPile.length > 0 && player.hand.length < 5) return {
599
+ success: false,
600
+ error: "canDraw"
601
+ };
602
+ game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;
603
+ emitEvent(game, {
604
+ type: "expirationUpdated",
605
+ expiresAt: game.expiresAt
606
+ });
607
+ player.hasNoPlayableCards = true;
608
+ const otherPlayer = game.players.find((p) => p !== player);
609
+ if (otherPlayer.hasNoPlayableCards) {
610
+ if (player.sidePile.length === 0 && otherPlayer.sidePile.length === 0) {
611
+ const cards = [...player.centerPile, ...otherPlayer.centerPile];
612
+ shuffleCards(cards);
613
+ player.sidePile.push(...cards.splice(0, 5));
614
+ emitEvent(game, {
615
+ type: "playerSidePileInitialized",
616
+ username: player.username,
617
+ numCards: player.sidePile.length
618
+ });
619
+ player.centerPile.push(...cards.splice(0, 1));
620
+ emitEvent(game, {
621
+ type: "playerCenterPileInitialized",
622
+ username: player.username,
623
+ card: player.centerPile[player.centerPile.length - 1]
624
+ });
625
+ otherPlayer.centerPile.push(...cards.splice(0, 1));
626
+ emitEvent(game, {
627
+ type: "playerCenterPileInitialized",
628
+ username: otherPlayer.username,
629
+ card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]
630
+ });
631
+ otherPlayer.sidePile.push(...cards.splice(0, 5));
632
+ emitEvent(game, {
633
+ type: "playerSidePileInitialized",
634
+ username: otherPlayer.username,
635
+ numCards: otherPlayer.sidePile.length
636
+ });
637
+ } else {
638
+ const playerSidePileCard = player.sidePile.pop();
639
+ player.centerPile.push(playerSidePileCard);
640
+ emitEvent(game, {
641
+ type: "cardDrawnFromSidePileToCenterPile",
642
+ username: player.username,
643
+ card: playerSidePileCard
644
+ });
645
+ const otherPlayerSidePileCard = otherPlayer.sidePile.pop();
646
+ otherPlayer.centerPile.push(otherPlayerSidePileCard);
647
+ emitEvent(game, {
648
+ type: "cardDrawnFromSidePileToCenterPile",
649
+ username: otherPlayer.username,
650
+ card: otherPlayerSidePileCard
651
+ });
652
+ }
653
+ player.hasNoPlayableCards = false;
654
+ otherPlayer.hasNoPlayableCards = false;
655
+ game.canPlayAt = Date.now() + CAN_PLAY_AT_DELAY_MS;
656
+ emitEvent(game, {
657
+ type: "canPlayAtUpdated",
658
+ canPlayAt: game.canPlayAt
659
+ });
660
+ }
661
+ return { success: true };
662
+ }
663
+ sendChat(gameId, playerId, text) {
664
+ const game = this.games.get(gameId);
665
+ if (!game) return {
666
+ success: false,
667
+ error: "gameNotFound"
668
+ };
669
+ const player = game.players.find((p) => p.id === playerId);
670
+ if (!player) return {
671
+ success: false,
672
+ error: "playerNotFound"
673
+ };
674
+ const message = {
675
+ id: crypto.randomUUID(),
676
+ username: player.username,
677
+ text
678
+ };
679
+ game.chatMessages.push(message);
680
+ emitEvent(game, {
681
+ type: "chat",
682
+ message
683
+ });
684
+ return { success: true };
685
+ }
686
+ startGame(gameId, playerId) {
687
+ const game = this.games.get(gameId);
688
+ if (!game) return {
689
+ success: false,
690
+ error: "gameNotFound"
691
+ };
692
+ const player = game.players.find((p) => p.id === playerId);
693
+ if (!player) return {
694
+ success: false,
695
+ error: "playerNotFound"
696
+ };
697
+ if (game.status !== "open") return {
698
+ success: false,
699
+ error: "invalidStatus"
700
+ };
701
+ if (game.players.indexOf(player) !== 0) return {
702
+ success: false,
703
+ error: "playerNotAdmin"
704
+ };
705
+ if (game.players.length < 2) return {
706
+ success: false,
707
+ error: "minPlayersNotReached"
708
+ };
709
+ const otherPlayer = game.players[1];
710
+ const cards = [...CARDS];
711
+ shuffleCards(cards);
712
+ player.sidePile.push(...cards.splice(0, 5));
713
+ emitEvent(game, {
714
+ type: "playerSidePileInitialized",
715
+ username: player.username,
716
+ numCards: player.sidePile.length
717
+ });
718
+ player.centerPile.push(...cards.splice(0, 1));
719
+ emitEvent(game, {
720
+ type: "playerCenterPileInitialized",
721
+ username: player.username,
722
+ card: player.centerPile[player.centerPile.length - 1]
723
+ });
724
+ otherPlayer.centerPile.push(...cards.splice(0, 1));
725
+ emitEvent(game, {
726
+ type: "playerCenterPileInitialized",
727
+ username: otherPlayer.username,
728
+ card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]
729
+ });
730
+ otherPlayer.sidePile.push(...cards.splice(0, 5));
731
+ emitEvent(game, {
732
+ type: "playerSidePileInitialized",
733
+ username: otherPlayer.username,
734
+ numCards: otherPlayer.sidePile.length
735
+ });
736
+ player.drawPile.push(...cards.splice(0, 15));
737
+ emitEvent(game, {
738
+ type: "playerDrawPileInitialized",
739
+ username: player.username,
740
+ numCards: player.drawPile.length
741
+ });
742
+ player.hand.push(...cards.splice(0, 5));
743
+ emitEventToPlayer(player, {
744
+ type: "handInitialized",
745
+ cards: player.hand
746
+ });
747
+ emitEvent(game, {
748
+ type: "playerHandInitialized",
749
+ username: player.username,
750
+ numCards: player.hand.length
751
+ });
752
+ otherPlayer.drawPile.push(...cards.splice(0, 15));
753
+ emitEvent(game, {
754
+ type: "playerDrawPileInitialized",
755
+ username: otherPlayer.username,
756
+ numCards: otherPlayer.drawPile.length
757
+ });
758
+ otherPlayer.hand.push(...cards.splice(0, 5));
759
+ emitEventToPlayer(otherPlayer, {
760
+ type: "handInitialized",
761
+ cards: otherPlayer.hand
762
+ });
763
+ emitEvent(game, {
764
+ type: "playerHandInitialized",
765
+ username: otherPlayer.username,
766
+ numCards: otherPlayer.hand.length
767
+ });
768
+ const startedGame = {
769
+ ...game,
770
+ status: "started",
771
+ expiresAt: Date.now() + EXPIRY_EXTENSION_MS,
772
+ canPlayAt: Date.now() + CAN_PLAY_AT_DELAY_MS
773
+ };
774
+ this.games.set(game.id, startedGame);
775
+ emitEvent(startedGame, { type: "gameStarted" });
776
+ emitEvent(startedGame, {
777
+ type: "expirationUpdated",
778
+ expiresAt: startedGame.expiresAt
779
+ });
780
+ emitEvent(startedGame, {
781
+ type: "canPlayAtUpdated",
782
+ canPlayAt: startedGame.canPlayAt
783
+ });
784
+ return { success: true };
785
+ }
786
+ };
787
+ //#endregion
788
+ export { Manager as t };
789
+
790
+ //# sourceMappingURL=manager-8x5AFyzq.mjs.map