Feat : add most token effects
This commit is contained in:
@@ -28,8 +28,11 @@ 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 { GameService } from '../services/games.service';
|
||||||
import { CardEffects } from 'src/cards/schemas/cards.types';
|
import { CardEffects, CardType } from 'src/cards/schemas/cards.types';
|
||||||
import { UseTokenDTO } from '../dto/use-token-dto';
|
import { UseTokenDTO } from '../dto/use-token-dto';
|
||||||
|
import { DamagePlayerDTO } from '../dto/damage-player-dto';
|
||||||
|
import { DamageChampionDTO } from '../dto/damage-champion-dto';
|
||||||
|
import { equal } from 'assert';
|
||||||
|
|
||||||
@ApiTags('turn')
|
@ApiTags('turn')
|
||||||
@Controller('games/:gameId/turn')
|
@Controller('games/:gameId/turn')
|
||||||
@@ -228,18 +231,27 @@ export class TurnController {
|
|||||||
throw new HttpException('Token not found', HttpStatus.NOT_FOUND);
|
throw new HttpException('Token not found', HttpStatus.NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetPlayer = findPlayer(useTokenDto.playerId, game);
|
const enemyTargetTokens = [
|
||||||
|
|
||||||
const enemyTargetToken = [
|
|
||||||
CardEffects.STUN,
|
CardEffects.STUN,
|
||||||
CardEffects.CONTROL_OPPOSING_CHAMPION_PASSIVE,
|
CardEffects.CONTROL_OPPOSING_CHAMPION_PASSIVE,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const marketTokens = [
|
||||||
|
CardEffects.STACK_NEXT_ACTION_BOUGHT,
|
||||||
|
CardEffects.STACK_NEXT_CARD_BOUGHT,
|
||||||
|
];
|
||||||
|
|
||||||
let targetCard: Card;
|
let targetCard: Card;
|
||||||
if (enemyTargetToken.includes(token.effect)) {
|
let targetPlayer = currentPlayer;
|
||||||
|
if (enemyTargetTokens.includes(token.effect)) {
|
||||||
|
targetPlayer = findPlayer(useTokenDto.playerId, game);
|
||||||
targetCard = targetPlayer.board.cards.find((c) =>
|
targetCard = targetPlayer.board.cards.find((c) =>
|
||||||
c._id.equals(useTokenDto.cardId),
|
c._id.equals(useTokenDto.cardId),
|
||||||
);
|
);
|
||||||
|
} else if (marketTokens.includes(token.effect)) {
|
||||||
|
targetCard =
|
||||||
|
game.market.cards.find((c) => c._id.equals(useTokenDto.cardId)) ??
|
||||||
|
game.fireGems.cards.find((c) => c._id.equals(useTokenDto.cardId));
|
||||||
} else {
|
} else {
|
||||||
targetCard = currentPlayer.board.cards.find((c) =>
|
targetCard = currentPlayer.board.cards.find((c) =>
|
||||||
c._id.equals(useTokenDto.cardId),
|
c._id.equals(useTokenDto.cardId),
|
||||||
@@ -249,6 +261,82 @@ export class TurnController {
|
|||||||
if (!targetCard) {
|
if (!targetCard) {
|
||||||
throw new HttpException('Card not found', HttpStatus.NOT_FOUND);
|
throw new HttpException('Card not found', HttpStatus.NOT_FOUND);
|
||||||
}
|
}
|
||||||
await this.turnService.useToken(game, currentPlayer, token, targetCard);
|
await this.turnService.useToken(game, targetPlayer, token, targetCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('damagePlayer/:playerId')
|
||||||
|
@ApiOperation({ summary: 'Consume damage points to damage a player' })
|
||||||
|
@UseGuards(AuthGuard)
|
||||||
|
async damagePlayer(
|
||||||
|
@Param('gameId') _gameId: string,
|
||||||
|
@Param('playerId') playerId: string,
|
||||||
|
@Param('gameId', GameStartedPipe) game: Document<Game> & Game,
|
||||||
|
@Body() damagePlayerDTO: DamagePlayerDTO,
|
||||||
|
@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 (damagePlayerDTO.amount > game.currentTurn.damage) {
|
||||||
|
throw new HttpException(
|
||||||
|
'You cannot deal more damage than what your current damage points',
|
||||||
|
HttpStatus.BAD_REQUEST,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetPlayer = findPlayer(playerId, game);
|
||||||
|
await this.turnService.damagePlayer(
|
||||||
|
game,
|
||||||
|
damagePlayerDTO.amount,
|
||||||
|
currentPlayer,
|
||||||
|
targetPlayer,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('damageChampion/:cardId')
|
||||||
|
@ApiOperation({ summary: 'Consume damage points to stun a champion' })
|
||||||
|
@UseGuards(AuthGuard)
|
||||||
|
async damageChampion(
|
||||||
|
@Param('gameId') _gameId: string,
|
||||||
|
@Param('cardId') _cardId: string,
|
||||||
|
@Param('gameId', GameStartedPipe) game: Document<Game> & Game,
|
||||||
|
@Param('cardId', CardPipe) card: Document<Card> & Card,
|
||||||
|
@Body() damageChampion: DamageChampionDTO,
|
||||||
|
@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 (card.defense > game.currentTurn.damage) {
|
||||||
|
throw new HttpException(
|
||||||
|
'You cannot deal more damage than what your current damage points',
|
||||||
|
HttpStatus.BAD_REQUEST,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetPlayer = findPlayer(damageChampion.player, game);
|
||||||
|
if (!targetPlayer) {
|
||||||
|
throw new HttpException('Player not found', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
if (card.cardType != CardType.CHAMPION) {
|
||||||
|
throw new HttpException('Card is not a champion', HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!targetPlayer.board.cards.some((c) => c._id.equals(card._id))) {
|
||||||
|
throw new HttpException(
|
||||||
|
'Champion not found in player board',
|
||||||
|
HttpStatus.NOT_FOUND,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class DamageChampionDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
player: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class DamagePlayerDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
amount: number;
|
||||||
|
}
|
||||||
@@ -309,7 +309,7 @@ export const tokenMappings = {
|
|||||||
eventEmitter: EventEmitter2,
|
eventEmitter: EventEmitter2,
|
||||||
session: mongoose.mongo.ClientSession,
|
session: mongoose.mongo.ClientSession,
|
||||||
) => {
|
) => {
|
||||||
if (card.cardType != CardType.CHAMPION) {
|
if (card.cardType != CardType.ACTION) {
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
'Cannot stack : Card is not an action',
|
'Cannot stack : Card is not an action',
|
||||||
HttpStatus.BAD_REQUEST,
|
HttpStatus.BAD_REQUEST,
|
||||||
@@ -322,6 +322,7 @@ export const tokenMappings = {
|
|||||||
player.stack,
|
player.stack,
|
||||||
session,
|
session,
|
||||||
);
|
);
|
||||||
|
await gameService.fillMarket(game);
|
||||||
},
|
},
|
||||||
[CardEffects.STACK_NEXT_CARD_BOUGHT]: async (
|
[CardEffects.STACK_NEXT_CARD_BOUGHT]: async (
|
||||||
game: Document<Game> & Game,
|
game: Document<Game> & Game,
|
||||||
@@ -345,6 +346,7 @@ export const tokenMappings = {
|
|||||||
player.stack,
|
player.stack,
|
||||||
session,
|
session,
|
||||||
);
|
);
|
||||||
|
await gameService.fillMarket(game);
|
||||||
},
|
},
|
||||||
[CardEffects.PLAY_NEXT_CARD_BOUGHT]: async (
|
[CardEffects.PLAY_NEXT_CARD_BOUGHT]: async (
|
||||||
game: Document<Game> & Game,
|
game: Document<Game> & Game,
|
||||||
@@ -368,6 +370,7 @@ export const tokenMappings = {
|
|||||||
player.board,
|
player.board,
|
||||||
session,
|
session,
|
||||||
);
|
);
|
||||||
|
await gameService.fillMarket(game);
|
||||||
},
|
},
|
||||||
[CardEffects.DRAW_AND_DISCARD]: async (
|
[CardEffects.DRAW_AND_DISCARD]: async (
|
||||||
game: Document<Game> & Game,
|
game: Document<Game> & Game,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
Injectable,
|
Injectable,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { InjectModel, InjectConnection } from '@nestjs/mongoose';
|
import { InjectModel, InjectConnection } from '@nestjs/mongoose';
|
||||||
import { Container, Game, Player } from '../schemas/game.schema';
|
import { Container, Game, Player, Team } from '../schemas/game.schema';
|
||||||
import mongoose, { Document, Model } from 'mongoose';
|
import mongoose, { Document, Model } from 'mongoose';
|
||||||
import { Card } from 'src/cards/schemas/cards.schema';
|
import { Card } from 'src/cards/schemas/cards.schema';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
@@ -248,4 +248,33 @@ export class GameService {
|
|||||||
|
|
||||||
await game.save({ session });
|
await game.save({ session });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WithTransaction
|
||||||
|
async killTeam(
|
||||||
|
game: Document<Game> & Game,
|
||||||
|
team: Team,
|
||||||
|
session?: mongoose.mongo.ClientSession,
|
||||||
|
) {
|
||||||
|
const index = game.teams.findIndex((t) => t._id.equals(team._id));
|
||||||
|
game.teams.splice(index, 1);
|
||||||
|
if (game.teams.length <= 1) {
|
||||||
|
await this.endGame(game, session);
|
||||||
|
}
|
||||||
|
this.eventEmitter.emit('sse.game.' + game._id.toHexString(), {
|
||||||
|
type: 'killTeam',
|
||||||
|
teamId: team._id,
|
||||||
|
});
|
||||||
|
await game.save({ session });
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithTransaction
|
||||||
|
async endGame(
|
||||||
|
game: Document<Game> & Game,
|
||||||
|
session?: mongoose.mongo.ClientSession,
|
||||||
|
) {
|
||||||
|
this.eventEmitter.emit('sse.game.' + game._id.toHexString(), {
|
||||||
|
type: 'endGame',
|
||||||
|
});
|
||||||
|
await game.deleteOne({ session });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
Inject,
|
Inject,
|
||||||
Injectable,
|
Injectable,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { Container, Game, Player } from '../schemas/game.schema';
|
import { Container, Game, Player, Team } from '../schemas/game.schema';
|
||||||
import mongoose, { Document, Model } from 'mongoose';
|
import mongoose, { Document, Model } from 'mongoose';
|
||||||
import { Card } from 'src/cards/schemas/cards.schema';
|
import { Card } from 'src/cards/schemas/cards.schema';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
@@ -16,7 +16,7 @@ import {
|
|||||||
CardType,
|
CardType,
|
||||||
EffectType,
|
EffectType,
|
||||||
} from 'src/cards/schemas/cards.types';
|
} from 'src/cards/schemas/cards.types';
|
||||||
import { WithTransaction } from '../utils';
|
import { getPlayerTeam, WithTransaction } from '../utils';
|
||||||
import {
|
import {
|
||||||
conditionsMappings,
|
conditionsMappings,
|
||||||
effectMappings,
|
effectMappings,
|
||||||
@@ -275,4 +275,36 @@ export class TurnService {
|
|||||||
});
|
});
|
||||||
await game.save({ session });
|
await game.save({ session });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WithTransaction
|
||||||
|
async damagePlayer(
|
||||||
|
game: Document<Game> & Game,
|
||||||
|
amount: number,
|
||||||
|
player: Player,
|
||||||
|
targetPlayer: Player,
|
||||||
|
session?: mongoose.mongo.ClientSession,
|
||||||
|
) {
|
||||||
|
const team = getPlayerTeam(game, targetPlayer);
|
||||||
|
team.health -= amount;
|
||||||
|
game.currentTurn.damage -= amount;
|
||||||
|
|
||||||
|
this.eventEmitter.emit('sse.game.' + game._id.toHexString(), {
|
||||||
|
type: 'currentTurn.updateDamage',
|
||||||
|
damage: game.currentTurn.damage,
|
||||||
|
operation: -amount,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.eventEmitter.emit('sse.game.' + game._id.toHexString(), {
|
||||||
|
type: 'team.updateHealth',
|
||||||
|
team: team._id,
|
||||||
|
health: team.health,
|
||||||
|
operation: -amount,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (team.health <= 0) {
|
||||||
|
this.gamesService.killTeam(game, team, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
await game.save({ session });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,11 @@ export function isInTeam(team: Team, player: Player) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getPlayerTeam(game: Game, player: Player) {
|
||||||
|
return game.teams.find((t) =>
|
||||||
|
t.players.some((p) => p._id.equals(player._id)),
|
||||||
|
);
|
||||||
|
}
|
||||||
export function WithTransaction(
|
export function WithTransaction(
|
||||||
target: any,
|
target: any,
|
||||||
propertyKey: string,
|
propertyKey: string,
|
||||||
@@ -66,6 +71,7 @@ export function WithTransaction(
|
|||||||
|
|
||||||
descriptor.value = function (...args: any[]) {
|
descriptor.value = function (...args: any[]) {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
if (args.at(-1) instanceof mongoose.mongo.ClientSession) {
|
if (args.at(-1) instanceof mongoose.mongo.ClientSession) {
|
||||||
const data = await originalFunc.apply(this, args).catch((e) => {
|
const data = await originalFunc.apply(this, args).catch((e) => {
|
||||||
if (e instanceof HttpException) {
|
if (e instanceof HttpException) {
|
||||||
@@ -99,6 +105,9 @@ export function WithTransaction(
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user