diff --git a/src/games/controllers/games.controller.ts b/src/games/controllers/games.controller.ts index 455fd59..577045d 100644 --- a/src/games/controllers/games.controller.ts +++ b/src/games/controllers/games.controller.ts @@ -66,6 +66,12 @@ export class GamesController { HttpStatus.FORBIDDEN, ); } + if (currentPlayer.discardMarkers || currentPlayer.fuckUMarkers) { + throw new HttpException( + 'You must consume all your discard markers before ending your turn', + HttpStatus.FORBIDDEN, + ); + } await this.gameService.endTurn(game); } diff --git a/src/games/controllers/turn.controller.ts b/src/games/controllers/turn.controller.ts index d8d6693..c9033f5 100644 --- a/src/games/controllers/turn.controller.ts +++ b/src/games/controllers/turn.controller.ts @@ -61,6 +61,12 @@ export class TurnController { HttpStatus.FORBIDDEN, ); } + if (currentPlayer.discardMarkers || currentPlayer.fuckUMarkers) { + throw new HttpException( + 'You cannot lock a card while having discard markers', + HttpStatus.BAD_REQUEST, + ); + } if (game.currentTurn.cardsLocked.some((c) => c._id.equals(card._id))) { throw new HttpException('Card already locked', HttpStatus.BAD_REQUEST); } @@ -92,6 +98,12 @@ export class TurnController { HttpStatus.FORBIDDEN, ); } + if (currentPlayer.discardMarkers || currentPlayer.fuckUMarkers) { + throw new HttpException( + 'You cannot buy a card while having discard markers', + HttpStatus.BAD_REQUEST, + ); + } if (!game.market.cards.some((c) => c._id.equals(card._id))) { throw new HttpException( 'Card not in current game market', @@ -126,6 +138,12 @@ export class TurnController { HttpStatus.FORBIDDEN, ); } + if (currentPlayer.discardMarkers || currentPlayer.fuckUMarkers) { + throw new HttpException( + 'You cannot buy a card while having discard markers', + HttpStatus.BAD_REQUEST, + ); + } if (game.fireGems.cards.length < 1) { throw new HttpException('No Gems left', HttpStatus.NOT_FOUND); } @@ -156,6 +174,12 @@ export class TurnController { HttpStatus.FORBIDDEN, ); } + if (currentPlayer.discardMarkers || currentPlayer.fuckUMarkers) { + throw new HttpException( + 'You cannot lock an effect while having discard markers', + HttpStatus.BAD_REQUEST, + ); + } if (game.currentTurn.lockedEffects.some((e) => e._id.equals(effect._id))) { throw new HttpException('Effect already locked', HttpStatus.BAD_REQUEST); } @@ -206,6 +230,14 @@ export class TurnController { throw new HttpException('Token not found', HttpStatus.NOT_FOUND); } await this.turnService.makeDiscard(game, targetToken, targetPlayer); + const index = game.currentTurn.tokens.findIndex((t) => + t._id.equals(targetToken._id), + ); + game.currentTurn.tokens.splice(index, 1); + this.eventEmitter.emit('sse.game.' + game._id.toHexString(), { + type: 'currentTurn.useToken', + tokenId: targetToken._id.toHexString(), + }); } @Post('useToken/:tokenId') @@ -227,6 +259,7 @@ export class TurnController { HttpStatus.FORBIDDEN, ); } + if (!game.currentTurn.tokens.some((t) => t._id.equals(token._id))) { throw new HttpException('Token not found', HttpStatus.NOT_FOUND); } @@ -239,6 +272,7 @@ export class TurnController { const marketTokens = [ CardEffects.STACK_NEXT_ACTION_BOUGHT, CardEffects.STACK_NEXT_CARD_BOUGHT, + CardEffects.PLAY_NEXT_CARD_BOUGHT, ]; let targetCard: Card; @@ -258,9 +292,18 @@ export class TurnController { ); } - if (!targetCard) { - throw new HttpException('Card not found', HttpStatus.NOT_FOUND); + if (token.effect != CardEffects.DRAW_AND_DISCARD) { + if (currentPlayer.discardMarkers || currentPlayer.fuckUMarkers) { + throw new HttpException( + 'You cannot use a token while having discard markers', + HttpStatus.BAD_REQUEST, + ); + } + if (!targetCard) { + throw new HttpException('Card not found', HttpStatus.NOT_FOUND); + } } + await this.turnService.useToken(game, targetPlayer, token, targetCard); } @@ -290,6 +333,12 @@ export class TurnController { } const targetPlayer = findPlayer(playerId, game); + if (targetPlayer.board.cards.some((c) => c.guard)) { + throw new HttpException( + 'You cannot target this player while there is a guard', + HttpStatus.BAD_REQUEST, + ); + } await this.turnService.damagePlayer( game, damagePlayerDTO.amount, @@ -339,6 +388,49 @@ export class TurnController { ); } + if (!card.guard) { + if (targetPlayer.board.cards.some((c) => c.guard)) { + throw new HttpException( + 'You cannot target this champion while there is a guard', + HttpStatus.BAD_REQUEST, + ); + } + } await this.turnService.damageChampion(game, targetPlayer, card); } + + @Post('discardCard/:cardId') + @ApiOperation({ + summary: 'Discard a card if you have fuckU or discard markers', + }) + @UseGuards(AuthGuard) + async discardCard( + @Param('gameId') _gameId: string, + @Param('cardId') _cardId: string, + @Param('gameId', GameStartedPipe) game: Document & Game, + @Param('cardId', CardPipe) card: Document & Card, + @Session() session: Record, + ) { + const currentPlayer = getPlayer(session, game); + const currentTeam = getCurrentTeam(game); + if (!isInTeam(currentTeam, currentPlayer)) { + throw new HttpException( + 'It is not your turn to play', + HttpStatus.FORBIDDEN, + ); + } + + if (currentPlayer.discardMarkers == 0 && currentPlayer.fuckUMarkers == 0) { + throw new HttpException( + 'You do not have any discard or fuckU markers', + HttpStatus.BAD_REQUEST, + ); + } + + if (!currentPlayer.board.cards.some((c) => c._id.equals(_cardId))) { + throw new HttpException('Card not found in board', HttpStatus.NOT_FOUND); + } + + await this.turnService.discardCard(game, currentPlayer, card); + } } diff --git a/src/games/schemas/game.schema.ts b/src/games/schemas/game.schema.ts index aa389dd..e62a462 100644 --- a/src/games/schemas/game.schema.ts +++ b/src/games/schemas/game.schema.ts @@ -49,6 +49,16 @@ export class PlayingTurn extends Types.ObjectId { @Prop({ default: 0 }) gold: number; + + @Prop({ + type: mongoose.Schema.Types.ObjectId, + ref: 'Effect', + autopopulate: false, + }) + drawAndDiscardCurrentEffect?: Effect; + + @Prop({ default: 0 }) + drawAndDiscardCurrentAmount: number; } @Schema() diff --git a/src/games/services/effect.functions.ts b/src/games/services/effect.functions.ts index ca6773f..87861f6 100644 --- a/src/games/services/effect.functions.ts +++ b/src/games/services/effect.functions.ts @@ -47,7 +47,10 @@ export async function removeToken( effect: Effect, eventEmitter: EventEmitter2, ) { - game.currentTurn.tokens.splice(game.currentTurn.tokens.indexOf(effect), 1); + game.currentTurn.tokens.splice( + game.currentTurn.tokens.findIndex((t) => t._id.equals(effect._id)), + 1, + ); eventEmitter.emit('sse.game.' + game._id.toHexString(), { type: 'currentTurn.removeToken', token: effect._id, @@ -322,7 +325,7 @@ export const tokenMappings = { player.stack, session, ); - await gameService.fillMarket(game); + await gameService.fillMarket(game, session); }, [CardEffects.STACK_NEXT_CARD_BOUGHT]: async ( game: Document & Game, @@ -370,20 +373,37 @@ export const tokenMappings = { player.board, session, ); - await gameService.fillMarket(game); + await gameService.fillMarket(game, session); }, [CardEffects.DRAW_AND_DISCARD]: async ( game: Document & Game, effect: Effect, player: Player, - card: Card, + _card: Card, gameService: GameService, turnService: TurnService, eventEmitter: EventEmitter2, session: mongoose.mongo.ClientSession, ) => { + if ( + game.currentTurn.drawAndDiscardCurrentEffect && + !game.currentTurn.drawAndDiscardCurrentEffect._id.equals(effect._id) + ) { + throw new HttpException( + 'You cannot use a token while having discard markers', + HttpStatus.BAD_REQUEST, + ); + } await gameService.drawToBoard(1, player, game, session); await player.discardMarkers++; + eventEmitter.emit('sse.game.' + game._id.toHexString(), { + type: 'player.addDiscardMarker', + operation: 1, + discardMarkers: player.discardMarkers, + playerId: player._id.toHexString(), + }); + game.currentTurn.drawAndDiscardCurrentAmount++; + game.currentTurn.drawAndDiscardCurrentEffect = effect; }, } as Record< CardEffects, diff --git a/src/games/services/games.service.ts b/src/games/services/games.service.ts index 4da68e2..62a8188 100644 --- a/src/games/services/games.service.ts +++ b/src/games/services/games.service.ts @@ -33,6 +33,27 @@ export class GameService { let currentTeam = getCurrentTeam(game); for (const player of currentTeam.players) { + if (player.discardMarkers > 0) { + this.eventEmitter.emit('sse.game.' + game._id.toHexString(), { + type: 'player.removeDiscardMarker', + operation: -player.discardMarkers, + discardMarkers: 0, + playerId: player._id.toHexString(), + }); + player.discardMarkers = 0; + } + + if (player.fuckUMarkers > 0) { + player.fuckUMarkers--; + this.eventEmitter.emit('sse.game.' + game._id.toHexString(), { + type: 'player.removeFuckUMarker', + operation: -player.fuckUMarkers, + fuckUMarkers: 0, + playerId: player._id.toHexString(), + }); + player.fuckUMarkers = 0; + } + await this.distributeCards( player.board.cards.filter((c) => !c.defense), player.board, diff --git a/src/games/services/turn.service.ts b/src/games/services/turn.service.ts index 7874278..0d95711 100644 --- a/src/games/services/turn.service.ts +++ b/src/games/services/turn.service.ts @@ -232,6 +232,12 @@ export class TurnService { session?: mongoose.mongo.ClientSession, ) { target.fuckUMarkers++; + this.eventEmitter.emit('sse.game.' + game._id.toHexString(), { + type: 'player.addFuckUMarker', + operation: 1, + fuckUMarkers: target.fuckUMarkers, + playerId: target._id.toHexString(), + }); const index = game.currentTurn.tokens.findIndex((t) => t._id.equals(token._id), ); @@ -265,14 +271,21 @@ export class TurnService { this.eventEmitter, session, ); - const index = game.currentTurn.tokens.findIndex((t) => - t._id.equals(token._id), - ); - game.currentTurn.tokens.splice(index, 1); - this.eventEmitter.emit('sse.game.' + game._id.toHexString(), { - type: 'currentTurn.useToken', - tokenId: token._id.toHexString(), - }); + if ( + token.effect != CardEffects.DRAW_AND_DISCARD || + (token.effect == CardEffects.DRAW_AND_DISCARD && + token.times >= game.currentTurn.drawAndDiscardCurrentAmount) + ) { + const index = game.currentTurn.tokens.findIndex((t) => + t._id.equals(token._id), + ); + game.currentTurn.tokens.splice(index, 1); + this.eventEmitter.emit('sse.game.' + game._id.toHexString(), { + type: 'currentTurn.useToken', + tokenId: token._id.toHexString(), + }); + } + await game.save({ session }); } @@ -333,4 +346,52 @@ export class TurnService { await game.save({ session }); } + + @WithTransaction + async discardCard( + game: Document & Game, + player: Player, + card: Card, + session?: mongoose.mongo.ClientSession, + ) { + await this.gamesService.distributeCards( + [card], + player.board, + player.discard, + game, + ); + if (player.discardMarkers > 0) { + player.discardMarkers--; + this.eventEmitter.emit('sse.game.' + game._id.toHexString(), { + type: 'player.removeDiscardMarker', + operation: -1, + discardMarkers: player.discardMarkers, + playerId: player._id.toHexString(), + }); + } else if (player.fuckUMarkers > 0) { + player.fuckUMarkers--; + this.eventEmitter.emit('sse.game.' + game._id.toHexString(), { + type: 'player.removeFuckUMarker', + operation: -1, + fuckUMarkers: player.fuckUMarkers, + playerId: player._id.toHexString(), + }); + } + + game.currentTurn.drawAndDiscardCurrentAmount = 0; + game.currentTurn.drawAndDiscardCurrentEffect = null; + // if (token) { + // const index = game.currentTurn.tokens.findIndex((t) => + // t._id.equals(token._id), + // ); + // game.currentTurn.tokens.splice(index, 1); + // this.eventEmitter.emit('sse.game.' + game._id.toHexString(), { + // type: 'currentTurn.useToken', + // tokenId: token._id.toHexString(), + // }); + // game.currentTurn.drawAndDiscardCurrentEffect = null; + // } + + await game.save({ session }); + } } diff --git a/src/games/utils.ts b/src/games/utils.ts index 3566364..3b39964 100644 --- a/src/games/utils.ts +++ b/src/games/utils.ts @@ -83,6 +83,7 @@ export function WithTransaction( HttpStatus.TOO_MANY_REQUESTS, ), ); + return; }); resolve(data); return data;