Feat : add Prepare token
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
Body,
|
||||||
Controller,
|
Controller,
|
||||||
HttpException,
|
HttpException,
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
@@ -9,23 +10,27 @@ import {
|
|||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { AuthGuard } from '../guards/auth.guard';
|
import { AuthGuard } from '../guards/auth.guard';
|
||||||
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
import { Game } from '../schemas/game.schema';
|
import { Game, Player } from '../schemas/game.schema';
|
||||||
import { Document, Model } from 'mongoose';
|
import { Document, Model } from 'mongoose';
|
||||||
import { GameStartedPipe } from '../pipe/game.pipe';
|
import { GameStartedPipe } from '../pipe/game.pipe';
|
||||||
|
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import { TurnService } from '../services/turn.service';
|
import { TurnService } from '../services/turn.service';
|
||||||
import { getPlayer, getCurrentTeam, isInTeam } from '../utils';
|
import { getPlayer, getCurrentTeam, isInTeam, findPlayer } from '../utils';
|
||||||
import { CardPipe } from '../pipe/card.pipe';
|
import { CardPipe } from '../pipe/card.pipe';
|
||||||
import { Card } from 'src/cards/schemas/cards.schema';
|
import { Card } from 'src/cards/schemas/cards.schema';
|
||||||
import { EffectPipe } from '../pipe/effect.pipe';
|
import { EffectPipe } from '../pipe/effect.pipe';
|
||||||
import { Effect } from 'src/cards/schemas/effect.schema';
|
import { Effect } from 'src/cards/schemas/effect.schema';
|
||||||
|
import { GameService } from '../services/games.service';
|
||||||
|
import { CardEffects } from 'src/cards/schemas/cards.types';
|
||||||
|
import { UseTokenDTO } from '../dto/use-token-dto';
|
||||||
|
|
||||||
@ApiTags('turn')
|
@ApiTags('turn')
|
||||||
@Controller('games/:gameId/turn')
|
@Controller('games/:gameId/turn')
|
||||||
export class TurnController {
|
export class TurnController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly turnService: TurnService,
|
private readonly turnService: TurnService,
|
||||||
|
private readonly gameService: GameService,
|
||||||
private eventEmitter: EventEmitter2,
|
private eventEmitter: EventEmitter2,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -88,6 +93,7 @@ export class TurnController {
|
|||||||
throw new HttpException('Not enough gold', HttpStatus.BAD_REQUEST);
|
throw new HttpException('Not enough gold', HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
await this.turnService.buyGeneric(game, currentPlayer, card, game.market);
|
await this.turnService.buyGeneric(game, currentPlayer, card, game.market);
|
||||||
|
await this.gameService.fillMarket(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('buyGem')
|
@Post('buyGem')
|
||||||
@@ -152,4 +158,97 @@ export class TurnController {
|
|||||||
|
|
||||||
await this.turnService.lockEffect(game, currentPlayer, effect, card);
|
await this.turnService.lockEffect(game, currentPlayer, effect, card);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post('makeDiscard/:playerId')
|
||||||
|
@ApiOperation({ summary: 'Use a token to make discard a player' })
|
||||||
|
@UseGuards(AuthGuard)
|
||||||
|
async makeDiscard(
|
||||||
|
@Param('gameId') _gameId: string,
|
||||||
|
@Param('playerId') _playerId: string,
|
||||||
|
@Param('gameId', GameStartedPipe) game: Document<Game> & Game,
|
||||||
|
@Session() session: Record<string, string>,
|
||||||
|
) {
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetPlayer = findPlayer(_playerId, game);
|
||||||
|
if (!isInTeam(currentTeam, targetPlayer)) {
|
||||||
|
throw new HttpException(
|
||||||
|
'You cannot target players in the same team as yours',
|
||||||
|
HttpStatus.FORBIDDEN,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetToken = game.currentTurn.tokens.find(
|
||||||
|
(t) => t.effect == CardEffects.MAKE_DISCARD,
|
||||||
|
);
|
||||||
|
if (!targetToken) {
|
||||||
|
throw new HttpException('Token not found', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
await this.turnService.makeDiscard(game, targetToken, targetPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('useToken/:tokenId')
|
||||||
|
@ApiOperation({ summary: 'Use a token' })
|
||||||
|
@UseGuards(AuthGuard)
|
||||||
|
async useToken(
|
||||||
|
@Param('gameId') _gameId: string,
|
||||||
|
@Param('tokenId') _tokenId: string,
|
||||||
|
@Param('gameId', GameStartedPipe) game: Document<Game> & Game,
|
||||||
|
@Param('tokenId', EffectPipe) token: Document<Effect> & Effect,
|
||||||
|
@Body() useTokenDto: UseTokenDTO,
|
||||||
|
@Session() session: Record<string, string>,
|
||||||
|
) {
|
||||||
|
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 (!game.currentTurn.tokens.some((t) => t._id.equals(token._id))) {
|
||||||
|
throw new HttpException('Token not found', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetPlayer = findPlayer(useTokenDto.playerId, game);
|
||||||
|
|
||||||
|
const enemyTargetToken = [
|
||||||
|
CardEffects.STUN,
|
||||||
|
CardEffects.CONTROL_OPPOSING_CHAMPION_PASSIVE,
|
||||||
|
];
|
||||||
|
if (enemyTargetToken.includes(token.effect)) {
|
||||||
|
const targetCard = targetPlayer.board.cards.find((c) =>
|
||||||
|
c._id.equals(useTokenDto.cardId),
|
||||||
|
);
|
||||||
|
if (!targetCard) {
|
||||||
|
throw new HttpException('Card not found', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
await this.turnService.useTokenOnEnemyBoard(
|
||||||
|
game,
|
||||||
|
targetPlayer,
|
||||||
|
token,
|
||||||
|
targetCard,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const targetCard = currentPlayer.board.cards.find((c) =>
|
||||||
|
c._id.equals(useTokenDto.cardId),
|
||||||
|
);
|
||||||
|
if (!targetCard) {
|
||||||
|
throw new HttpException('Card not found', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
await this.turnService.useTokenOnEnemyBoard(
|
||||||
|
game,
|
||||||
|
currentPlayer,
|
||||||
|
token,
|
||||||
|
targetCard,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export class UseTokenDTO {
|
||||||
|
playerId: string;
|
||||||
|
cardId: string;
|
||||||
|
}
|
||||||
@@ -2,7 +2,12 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
|||||||
import { Game, Player } from '../schemas/game.schema';
|
import { Game, Player } from '../schemas/game.schema';
|
||||||
import mongoose, { Document } from 'mongoose';
|
import mongoose, { Document } from 'mongoose';
|
||||||
import { Card } from 'src/cards/schemas/cards.schema';
|
import { Card } from 'src/cards/schemas/cards.schema';
|
||||||
import { CardEffects, EffectType, Per } from 'src/cards/schemas/cards.types';
|
import {
|
||||||
|
CardEffects,
|
||||||
|
CardType,
|
||||||
|
EffectType,
|
||||||
|
Per,
|
||||||
|
} from 'src/cards/schemas/cards.types';
|
||||||
import { Effect, EffectCondition } from 'src/cards/schemas/effect.schema';
|
import { Effect, EffectCondition } from 'src/cards/schemas/effect.schema';
|
||||||
import { TurnService } from './turn.service';
|
import { TurnService } from './turn.service';
|
||||||
import { GameService } from './games.service';
|
import { GameService } from './games.service';
|
||||||
@@ -165,6 +170,53 @@ export const effectMappings = {
|
|||||||
) => Promise<void>
|
) => Promise<void>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
export const tokenMappings = {
|
||||||
|
[CardEffects.PREPARE]: async (
|
||||||
|
game: Document<Game> & Game,
|
||||||
|
effect: Effect,
|
||||||
|
player: Player,
|
||||||
|
card: Card,
|
||||||
|
gameService: GameService,
|
||||||
|
eventEmitter: EventEmitter2,
|
||||||
|
_session: mongoose.mongo.ClientSession,
|
||||||
|
) => {
|
||||||
|
if (card.cardType !== CardType.CHAMPION) {
|
||||||
|
throw new Error('Cannot Prepare : Card is not a champion');
|
||||||
|
}
|
||||||
|
const targetEffects = card.effects.filter(
|
||||||
|
(e) => e.condition.effectId == EffectType.CHAMPION_ACTION,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!targetEffects.every((e) =>
|
||||||
|
game.currentTurn.lockedEffects.some((ee) => ee._id.equals(e._id)),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
throw new Error('Cannot Prepare : champion effect not locked');
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const e of targetEffects) {
|
||||||
|
const index = game.currentTurn.lockedEffects.findIndex((ee) =>
|
||||||
|
ee._id.equals(e._id),
|
||||||
|
);
|
||||||
|
game.currentTurn.lockedEffects.splice(index, 1);
|
||||||
|
eventEmitter.emit('sse.game.' + game._id.toHexString(), {
|
||||||
|
type: 'unlockEffect',
|
||||||
|
effect: effect._id.toHexString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[CardEffects.STUN]: addToken,
|
||||||
|
[CardEffects.SACRIFICE]: addToken,
|
||||||
|
[CardEffects.DRAW_AND_DISCARD]: addToken,
|
||||||
|
[CardEffects.MAKE_DISCARD]: addToken,
|
||||||
|
[CardEffects.RESTACK_DISCARDED_CHAMPION]: addToken,
|
||||||
|
[CardEffects.RESTACK_DISCARDED_CARD]: addToken,
|
||||||
|
[CardEffects.STACK_NEXT_ACTION_BOUGHT]: addToken,
|
||||||
|
[CardEffects.STACK_NEXT_CARD_BOUGHT]: addToken,
|
||||||
|
[CardEffects.PLAY_NEXT_CARD_BOUGHT]: addToken,
|
||||||
|
};
|
||||||
|
|
||||||
export const conditionsMappings = {
|
export const conditionsMappings = {
|
||||||
[EffectType.CHAMPION_ACTION]: async () => true,
|
[EffectType.CHAMPION_ACTION]: async () => true,
|
||||||
[EffectType.FACTION_COMBO]: async (
|
[EffectType.FACTION_COMBO]: async (
|
||||||
|
|||||||
@@ -223,4 +223,42 @@ export class TurnService {
|
|||||||
);
|
);
|
||||||
await game.save({ session });
|
await game.save({ session });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WithTransaction
|
||||||
|
async makeDiscard(
|
||||||
|
game: Document<Game> & Game,
|
||||||
|
token: Effect,
|
||||||
|
target: Player,
|
||||||
|
session?: mongoose.mongo.ClientSession,
|
||||||
|
) {
|
||||||
|
target.fuckUMarkers++;
|
||||||
|
const index = game.currentTurn.tokens.findIndex((t) =>
|
||||||
|
t._id.equals(token._id),
|
||||||
|
);
|
||||||
|
if (index == -1) {
|
||||||
|
throw new Error('Token not found');
|
||||||
|
}
|
||||||
|
game.currentTurn.tokens.splice(index, 1);
|
||||||
|
|
||||||
|
await game.save({ session });
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithTransaction
|
||||||
|
async useToken(
|
||||||
|
game: Document<Game> & Game,
|
||||||
|
token: Effect,
|
||||||
|
target: Card,
|
||||||
|
session?: mongoose.mongo.ClientSession,
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithTransaction
|
||||||
|
async useTokenOnEnemyBoard(
|
||||||
|
game: Document<Game> & Game,
|
||||||
|
targetPlayer: Player,
|
||||||
|
token: Effect,
|
||||||
|
target: Card,
|
||||||
|
session?: mongoose.mongo.ClientSession,
|
||||||
|
) {}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-5
@@ -24,17 +24,19 @@ export function getPlayer(session: Record<string, any>, game: Game) {
|
|||||||
if (!user) {
|
if (!user) {
|
||||||
throw new HttpException('Please log in', HttpStatus.UNAUTHORIZED);
|
throw new HttpException('Please log in', HttpStatus.UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return findPlayer(user._id, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findPlayer(playerId: string, game: Game) {
|
||||||
for (const team of game.teams) {
|
for (const team of game.teams) {
|
||||||
for (const player of team.players) {
|
for (const player of team.players) {
|
||||||
if (player.user._id.equals(user._id)) {
|
if (player.user._id.equals(playerId)) {
|
||||||
return player as Document<Player> & Player;
|
return player as Document<Player> & Player;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new HttpException(
|
throw new HttpException('Player not found in game', HttpStatus.FORBIDDEN);
|
||||||
'You are not part of this game',
|
|
||||||
HttpStatus.FORBIDDEN,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isInTeam(team: Team, player: Player) {
|
export function isInTeam(team: Team, player: Player) {
|
||||||
|
|||||||
Reference in New Issue
Block a user