@hellacardgames/speed 0.8.0 → 0.8.1

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.
@@ -0,0 +1,907 @@
1
+ let _hellacardgames_lib = require("@hellacardgames/lib");
2
+ //#region src/game/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/game/actions/createGame.ts
269
+ function createGame(userId, username) {
270
+ const player = {
271
+ id: crypto.randomUUID(),
272
+ userId,
273
+ username,
274
+ events: [],
275
+ hand: [],
276
+ drawPile: [],
277
+ sidePile: [],
278
+ centerPile: [],
279
+ hasNoPlayableCards: false
280
+ };
281
+ const createdAt = Date.now();
282
+ return {
283
+ game: {
284
+ status: "created",
285
+ id: crypto.randomUUID(),
286
+ createdAt,
287
+ expiresAt: createdAt + EXPIRY_EXTENSION_MS,
288
+ chatMessages: [],
289
+ players: [player]
290
+ },
291
+ playerId: player.id
292
+ };
293
+ }
294
+ //#endregion
295
+ //#region src/game/lib/emitEvent.ts
296
+ function emitEvent$1(game, data) {
297
+ const event = {
298
+ ...data,
299
+ id: crypto.randomUUID()
300
+ };
301
+ for (const p of game.players) p.events.push(event);
302
+ }
303
+ //#endregion
304
+ //#region src/game/lib/emitEventToPlayer.ts
305
+ function emitEventToPlayer(player, data) {
306
+ player.events.push({
307
+ ...data,
308
+ id: crypto.randomUUID()
309
+ });
310
+ }
311
+ //#endregion
312
+ //#region src/game/actions/drawCard.ts
313
+ function drawCard(game, playerId) {
314
+ const player = game.players.find((p) => p.id === playerId);
315
+ if (!player) return {
316
+ success: false,
317
+ error: "playerNotFound"
318
+ };
319
+ if (Date.now() < game.canPlayAt) return {
320
+ success: false,
321
+ error: "canPlayAtNotReached"
322
+ };
323
+ if (player.hand.length >= 5) return {
324
+ success: false,
325
+ error: "handFull"
326
+ };
327
+ if (player.drawPile.length === 0) return {
328
+ success: false,
329
+ error: "drawPileEmpty"
330
+ };
331
+ game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;
332
+ emitEvent$1(game, {
333
+ type: "expirationUpdated",
334
+ expiresAt: game.expiresAt
335
+ });
336
+ const card = player.drawPile.pop();
337
+ player.hand.push(card);
338
+ emitEventToPlayer(player, {
339
+ type: "drewCard",
340
+ card
341
+ });
342
+ emitEvent$1(game, {
343
+ type: "playerDrewCard",
344
+ username: player.username
345
+ });
346
+ return {
347
+ success: true,
348
+ game
349
+ };
350
+ }
351
+ //#endregion
352
+ //#region src/game/actions/getClientStateAndClearEvents.ts
353
+ function getClientStateAndClearEvents(game, playerId) {
354
+ const player = game.players.find((p) => p.id === playerId);
355
+ if (!player) return {
356
+ success: false,
357
+ error: "playerNotFound"
358
+ };
359
+ const state = {
360
+ status: game.status,
361
+ gameId: game.id,
362
+ playerId,
363
+ username: player.username,
364
+ players: game.players.map((p) => ({
365
+ username: p.username,
366
+ handSize: p.hand.length,
367
+ drawPileSize: p.drawPile.length,
368
+ sidePileSize: p.sidePile.length,
369
+ centerPileTopCard: p.centerPile.length ? p.centerPile[p.centerPile.length - 1] : null
370
+ })),
371
+ expiresAt: game.expiresAt,
372
+ chatMessages: game.chatMessages,
373
+ hand: player.hand,
374
+ canPlayAt: game.status === "started" ? game.canPlayAt : null
375
+ };
376
+ player.events.length = 0;
377
+ return {
378
+ success: true,
379
+ state,
380
+ game
381
+ };
382
+ }
383
+ //#endregion
384
+ //#region src/game/actions/getEventsAndClearAcknowledged.ts
385
+ function getEventsAndClearAcknowledged(game, playerId, lastReadId) {
386
+ const player = game.players.find((p) => p.id === playerId);
387
+ if (!player) return {
388
+ success: false,
389
+ error: "playerNotFound"
390
+ };
391
+ const result = (0, _hellacardgames_lib.getEventsAndClearAcknowledged)(game, player.id, lastReadId);
392
+ return {
393
+ success: true,
394
+ events: result.events,
395
+ game: result.game
396
+ };
397
+ }
398
+ //#endregion
399
+ //#region src/game/actions/joinGame.ts
400
+ function joinGame(game, userId, username) {
401
+ if (game.players.length === 2) return {
402
+ success: false,
403
+ error: "maxPlayersReached"
404
+ };
405
+ if (game.players.find((p) => p.userId === userId)) return {
406
+ success: false,
407
+ error: "alreadyInGame"
408
+ };
409
+ const player = {
410
+ id: crypto.randomUUID(),
411
+ userId,
412
+ username,
413
+ events: [],
414
+ hand: [],
415
+ drawPile: [],
416
+ sidePile: [],
417
+ centerPile: [],
418
+ hasNoPlayableCards: false
419
+ };
420
+ game.players.push(player);
421
+ emitEvent$1(game, {
422
+ type: "playerJoined",
423
+ username
424
+ });
425
+ return {
426
+ success: true,
427
+ game,
428
+ playerId: player.id
429
+ };
430
+ }
431
+ //#endregion
432
+ //#region src/game/actions/leaveGame.ts
433
+ function leaveGame(game, playerId) {
434
+ const playerIndex = game.players.findIndex((p) => p.id === playerId);
435
+ if (playerIndex === -1) return {
436
+ success: false,
437
+ error: "playerNotFound"
438
+ };
439
+ const player = game.players[playerIndex];
440
+ emitEvent$1(game, {
441
+ type: "playerLeft",
442
+ username: player.username
443
+ });
444
+ game.players.splice(playerIndex, 1);
445
+ if (game.status === "started" && game.players.length < 2) {
446
+ const forfeitedGame = {
447
+ ...game,
448
+ status: "forfeited",
449
+ expiresAt: Date.now() + EXPIRY_EXTENSION_MS
450
+ };
451
+ emitEvent$1(forfeitedGame, { type: "gameForfeited" });
452
+ emitEvent$1(forfeitedGame, {
453
+ type: "expirationUpdated",
454
+ expiresAt: forfeitedGame.expiresAt
455
+ });
456
+ }
457
+ return {
458
+ success: true,
459
+ game
460
+ };
461
+ }
462
+ //#endregion
463
+ //#region src/game/lib/isCardPlayable.ts
464
+ function isCardPlayable(card, targetPile) {
465
+ const targetCard = targetPile[targetPile.length - 1];
466
+ return Math.abs(card.rank - targetCard.rank) % 11 === 1;
467
+ }
468
+ //#endregion
469
+ //#region src/game/lib/hasPlayableCard.ts
470
+ function hasPlayableCard(player, game) {
471
+ const otherPlayer = game.players.find((p) => p !== player);
472
+ const targetPile1 = player.centerPile;
473
+ const targetPile2 = otherPlayer.centerPile;
474
+ for (const card of player.hand) if (isCardPlayable(card, targetPile1) || isCardPlayable(card, targetPile2)) return true;
475
+ return false;
476
+ }
477
+ //#endregion
478
+ //#region src/game/actions/playCard.ts
479
+ function playCard(game, playerId, cardId, isForOtherPlayerPile) {
480
+ const player = game.players.find((p) => p.id === playerId);
481
+ if (!player) return {
482
+ success: false,
483
+ error: "playerNotFound"
484
+ };
485
+ if (Date.now() < game.canPlayAt) return {
486
+ success: false,
487
+ error: "canPlayAtNotReached"
488
+ };
489
+ const cardIndex = player.hand.findIndex((c) => c.id === cardId);
490
+ if (cardIndex === -1) return {
491
+ success: false,
492
+ error: "cardNotFound"
493
+ };
494
+ const otherPlayer = game.players.find((p) => p !== player);
495
+ const targetPile = isForOtherPlayerPile ? otherPlayer.centerPile : player.centerPile;
496
+ const card = player.hand[cardIndex];
497
+ if (!isCardPlayable(card, targetPile)) return {
498
+ success: false,
499
+ error: "cardNotPlayable"
500
+ };
501
+ game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;
502
+ emitEvent$1(game, {
503
+ type: "expirationUpdated",
504
+ expiresAt: game.expiresAt
505
+ });
506
+ player.hand.splice(cardIndex, 1);
507
+ targetPile.push(card);
508
+ emitEvent$1(game, {
509
+ type: "cardPlayed",
510
+ username: player.username,
511
+ card,
512
+ isForOtherPlayerPile
513
+ });
514
+ if (otherPlayer.hasNoPlayableCards && hasPlayableCard(otherPlayer, game)) otherPlayer.hasNoPlayableCards = false;
515
+ if (player.hand.length === 0 && player.drawPile.length === 0) {
516
+ emitEvent$1(game, { type: "gameCompleted" });
517
+ return {
518
+ success: true,
519
+ game: {
520
+ ...game,
521
+ status: "completed"
522
+ }
523
+ };
524
+ }
525
+ return {
526
+ success: true,
527
+ game
528
+ };
529
+ }
530
+ //#endregion
531
+ //#region src/game/lib/shuffleCards.ts
532
+ function shuffleCards(cards) {
533
+ for (let i = cards.length - 1; i > 0; i--) {
534
+ const j = Math.floor(Math.random() * (i + 1));
535
+ [cards[i], cards[j]] = [cards[j], cards[i]];
536
+ }
537
+ }
538
+ //#endregion
539
+ //#region src/game/actions/reportNoPlayableCards.ts
540
+ function reportNoPlayableCards(game, playerId) {
541
+ const player = game.players.find((p) => p.id === playerId);
542
+ if (!player) return {
543
+ success: false,
544
+ error: "playerNotFound"
545
+ };
546
+ if (Date.now() < game.canPlayAt) return {
547
+ success: false,
548
+ error: "canPlayAtNotReached"
549
+ };
550
+ if (player.hasNoPlayableCards) return {
551
+ success: false,
552
+ error: "alreadyReported"
553
+ };
554
+ if (hasPlayableCard(player, game)) return {
555
+ success: false,
556
+ error: "hasPlayableCard"
557
+ };
558
+ if (player.drawPile.length > 0 && player.hand.length < 5) return {
559
+ success: false,
560
+ error: "canDraw"
561
+ };
562
+ game.expiresAt = Date.now() + EXPIRY_EXTENSION_MS;
563
+ emitEvent$1(game, {
564
+ type: "expirationUpdated",
565
+ expiresAt: game.expiresAt
566
+ });
567
+ player.hasNoPlayableCards = true;
568
+ const otherPlayer = game.players.find((p) => p !== player);
569
+ if (otherPlayer.hasNoPlayableCards) {
570
+ if (player.sidePile.length === 0 && otherPlayer.sidePile.length === 0) {
571
+ const cards = [...player.centerPile, ...otherPlayer.centerPile];
572
+ shuffleCards(cards);
573
+ player.sidePile.push(...cards.splice(0, 5));
574
+ emitEvent$1(game, {
575
+ type: "playerSidePileInitialized",
576
+ username: player.username,
577
+ numCards: player.sidePile.length
578
+ });
579
+ player.centerPile.push(...cards.splice(0, 1));
580
+ emitEvent$1(game, {
581
+ type: "playerCenterPileInitialized",
582
+ username: player.username,
583
+ card: player.centerPile[player.centerPile.length - 1]
584
+ });
585
+ otherPlayer.centerPile.push(...cards.splice(0, 1));
586
+ emitEvent$1(game, {
587
+ type: "playerCenterPileInitialized",
588
+ username: otherPlayer.username,
589
+ card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]
590
+ });
591
+ otherPlayer.sidePile.push(...cards.splice(0, 5));
592
+ emitEvent$1(game, {
593
+ type: "playerSidePileInitialized",
594
+ username: otherPlayer.username,
595
+ numCards: otherPlayer.sidePile.length
596
+ });
597
+ } else {
598
+ const playerSidePileCard = player.sidePile.pop();
599
+ player.centerPile.push(playerSidePileCard);
600
+ emitEvent$1(game, {
601
+ type: "cardDrawnFromSidePileToCenterPile",
602
+ username: player.username,
603
+ card: playerSidePileCard
604
+ });
605
+ const otherPlayerSidePileCard = otherPlayer.sidePile.pop();
606
+ otherPlayer.centerPile.push(otherPlayerSidePileCard);
607
+ emitEvent$1(game, {
608
+ type: "cardDrawnFromSidePileToCenterPile",
609
+ username: otherPlayer.username,
610
+ card: otherPlayerSidePileCard
611
+ });
612
+ }
613
+ player.hasNoPlayableCards = false;
614
+ otherPlayer.hasNoPlayableCards = false;
615
+ game.canPlayAt = Date.now() + CAN_PLAY_AT_DELAY_MS;
616
+ emitEvent$1(game, {
617
+ type: "canPlayAtUpdated",
618
+ canPlayAt: game.canPlayAt
619
+ });
620
+ }
621
+ return {
622
+ success: true,
623
+ game
624
+ };
625
+ }
626
+ //#endregion
627
+ //#region src/game/actions/sendChat.ts
628
+ function sendChat(game, playerId, text) {
629
+ const player = game.players.find((p) => p.id === playerId);
630
+ if (!player) return {
631
+ success: false,
632
+ error: "playerNotFound"
633
+ };
634
+ const message = {
635
+ id: crypto.randomUUID(),
636
+ username: player.username,
637
+ text
638
+ };
639
+ game = {
640
+ ...game,
641
+ chatMessages: (0, _hellacardgames_lib.addItemToCollection)(game.chatMessages, message)
642
+ };
643
+ game = (0, _hellacardgames_lib.emitEvent)(game, {
644
+ type: "chat",
645
+ message
646
+ });
647
+ return {
648
+ success: true,
649
+ game
650
+ };
651
+ }
652
+ //#endregion
653
+ //#region src/game/actions/startGame.ts
654
+ function startGame(game, playerId) {
655
+ const player = game.players.find((p) => p.id === playerId);
656
+ if (!player) return {
657
+ success: false,
658
+ error: "playerNotFound"
659
+ };
660
+ if (game.players.indexOf(player) !== 0) return {
661
+ success: false,
662
+ error: "playerNotAdmin"
663
+ };
664
+ if (game.players.length < 2) return {
665
+ success: false,
666
+ error: "minPlayersNotReached"
667
+ };
668
+ const otherPlayer = game.players[1];
669
+ const cards = [...CARDS];
670
+ shuffleCards(cards);
671
+ player.sidePile.push(...cards.splice(0, 5));
672
+ emitEvent$1(game, {
673
+ type: "playerSidePileInitialized",
674
+ username: player.username,
675
+ numCards: player.sidePile.length
676
+ });
677
+ player.centerPile.push(...cards.splice(0, 1));
678
+ emitEvent$1(game, {
679
+ type: "playerCenterPileInitialized",
680
+ username: player.username,
681
+ card: player.centerPile[player.centerPile.length - 1]
682
+ });
683
+ otherPlayer.centerPile.push(...cards.splice(0, 1));
684
+ emitEvent$1(game, {
685
+ type: "playerCenterPileInitialized",
686
+ username: otherPlayer.username,
687
+ card: otherPlayer.centerPile[otherPlayer.centerPile.length - 1]
688
+ });
689
+ otherPlayer.sidePile.push(...cards.splice(0, 5));
690
+ emitEvent$1(game, {
691
+ type: "playerSidePileInitialized",
692
+ username: otherPlayer.username,
693
+ numCards: otherPlayer.sidePile.length
694
+ });
695
+ player.drawPile.push(...cards.splice(0, 15));
696
+ emitEvent$1(game, {
697
+ type: "playerDrawPileInitialized",
698
+ username: player.username,
699
+ numCards: player.drawPile.length
700
+ });
701
+ player.hand.push(...cards.splice(0, 5));
702
+ emitEventToPlayer(player, {
703
+ type: "handInitialized",
704
+ cards: player.hand
705
+ });
706
+ emitEvent$1(game, {
707
+ type: "playerHandInitialized",
708
+ username: player.username,
709
+ numCards: player.hand.length
710
+ });
711
+ otherPlayer.drawPile.push(...cards.splice(0, 15));
712
+ emitEvent$1(game, {
713
+ type: "playerDrawPileInitialized",
714
+ username: otherPlayer.username,
715
+ numCards: otherPlayer.drawPile.length
716
+ });
717
+ otherPlayer.hand.push(...cards.splice(0, 5));
718
+ emitEventToPlayer(otherPlayer, {
719
+ type: "handInitialized",
720
+ cards: otherPlayer.hand
721
+ });
722
+ emitEvent$1(game, {
723
+ type: "playerHandInitialized",
724
+ username: otherPlayer.username,
725
+ numCards: otherPlayer.hand.length
726
+ });
727
+ const startedGame = {
728
+ ...game,
729
+ status: "started",
730
+ expiresAt: Date.now() + EXPIRY_EXTENSION_MS,
731
+ canPlayAt: Date.now() + CAN_PLAY_AT_DELAY_MS
732
+ };
733
+ emitEvent$1(startedGame, { type: "gameStarted" });
734
+ emitEvent$1(startedGame, {
735
+ type: "expirationUpdated",
736
+ expiresAt: startedGame.expiresAt
737
+ });
738
+ emitEvent$1(startedGame, {
739
+ type: "canPlayAtUpdated",
740
+ canPlayAt: startedGame.canPlayAt
741
+ });
742
+ return {
743
+ success: true,
744
+ game: startedGame
745
+ };
746
+ }
747
+ //#endregion
748
+ //#region src/manager/Manager.ts
749
+ var Manager = class extends _hellacardgames_lib.ManagerBase {
750
+ createGame(userId, username) {
751
+ if (this.games.size === this.maxGames) return {
752
+ success: false,
753
+ error: "maxGamesReached"
754
+ };
755
+ const result = createGame(userId, username);
756
+ this.games.set(result.game.id, result.game);
757
+ return {
758
+ success: true,
759
+ gameId: result.game.id,
760
+ playerId: result.playerId
761
+ };
762
+ }
763
+ drawCard(gameId, playerId) {
764
+ const game = this.games.get(gameId);
765
+ if (!game) return {
766
+ success: false,
767
+ error: "gameNotFound"
768
+ };
769
+ if (game.status !== "started") return {
770
+ success: false,
771
+ error: "invalidStatus"
772
+ };
773
+ const result = drawCard(game, playerId);
774
+ if (!result.success) return result;
775
+ this.games.set(gameId, result.game);
776
+ return { success: true };
777
+ }
778
+ getClientStateAndClearEvents(gameId, playerId) {
779
+ const game = this.games.get(gameId);
780
+ if (!game) return {
781
+ success: false,
782
+ error: "gameNotFound"
783
+ };
784
+ const result = getClientStateAndClearEvents(game, playerId);
785
+ if (!result.success) return result;
786
+ this.games.set(gameId, result.game);
787
+ return {
788
+ success: true,
789
+ state: result.state
790
+ };
791
+ }
792
+ getEventsAndClearAcknowledged(gameId, playerId, lastReadId) {
793
+ const game = this.games.get(gameId);
794
+ if (!game) return {
795
+ success: false,
796
+ error: "gameNotFound"
797
+ };
798
+ const result = getEventsAndClearAcknowledged(game, playerId, lastReadId);
799
+ if (!result.success) return result;
800
+ this.games.set(gameId, result.game);
801
+ return {
802
+ success: true,
803
+ events: result.events
804
+ };
805
+ }
806
+ getJoinableGames() {
807
+ return { games: Array.from(this.games.values()).filter((g) => g.status === "created" && g.players.length < 2).map((g) => ({
808
+ id: g.id,
809
+ numPlayers: g.players.length
810
+ })) };
811
+ }
812
+ joinGame(gameId, userId, username) {
813
+ const game = this.games.get(gameId);
814
+ if (!game) return {
815
+ success: false,
816
+ error: "gameNotFound"
817
+ };
818
+ if (game.status !== "created") return {
819
+ success: false,
820
+ error: "invalidStatus"
821
+ };
822
+ const result = joinGame(game, userId, username);
823
+ if (!result.success) return result;
824
+ this.games.set(gameId, result.game);
825
+ return {
826
+ success: true,
827
+ playerId: result.playerId
828
+ };
829
+ }
830
+ leaveGame(gameId, playerId) {
831
+ const game = this.games.get(gameId);
832
+ if (!game) return {
833
+ success: false,
834
+ error: "gameNotFound"
835
+ };
836
+ const result = leaveGame(game, playerId);
837
+ if (!result.success) return result;
838
+ if (result.game.players.length > 0) this.games.set(gameId, result.game);
839
+ else this.games.delete(gameId);
840
+ return { success: true };
841
+ }
842
+ playCard(gameId, playerId, cardId, isForOtherPlayerPile) {
843
+ const game = this.games.get(gameId);
844
+ if (!game) return {
845
+ success: false,
846
+ error: "gameNotFound"
847
+ };
848
+ if (game.status !== "started") return {
849
+ success: false,
850
+ error: "invalidStatus"
851
+ };
852
+ const result = playCard(game, playerId, cardId, isForOtherPlayerPile);
853
+ if (!result.success) return result;
854
+ this.games.set(gameId, result.game);
855
+ return { success: true };
856
+ }
857
+ reportNoPlayableCards(gameId, playerId) {
858
+ const game = this.games.get(gameId);
859
+ if (!game) return {
860
+ success: false,
861
+ error: "gameNotFound"
862
+ };
863
+ if (game.status !== "started") return {
864
+ success: false,
865
+ error: "invalidStatus"
866
+ };
867
+ const result = reportNoPlayableCards(game, playerId);
868
+ if (!result.success) return result;
869
+ this.games.set(gameId, result.game);
870
+ return { success: true };
871
+ }
872
+ sendChat(gameId, playerId, text) {
873
+ const game = this.games.get(gameId);
874
+ if (!game) return {
875
+ success: false,
876
+ error: "gameNotFound"
877
+ };
878
+ const result = sendChat(game, playerId, text);
879
+ if (!result.success) return result;
880
+ this.games.set(gameId, result.game);
881
+ return { success: true };
882
+ }
883
+ startGame(gameId, playerId) {
884
+ const game = this.games.get(gameId);
885
+ if (!game) return {
886
+ success: false,
887
+ error: "gameNotFound"
888
+ };
889
+ if (game.status !== "created") return {
890
+ success: false,
891
+ error: "invalidStatus"
892
+ };
893
+ const result = startGame(game, playerId);
894
+ if (!result.success) return result;
895
+ this.games.set(gameId, result.game);
896
+ return { success: true };
897
+ }
898
+ };
899
+ //#endregion
900
+ Object.defineProperty(exports, "Manager", {
901
+ enumerable: true,
902
+ get: function() {
903
+ return Manager;
904
+ }
905
+ });
906
+
907
+ //# sourceMappingURL=manager-0r8lvLRR.cjs.map