Files
back-ts/src/games/services/games.lobby.service.ts
T
2024-06-11 18:57:01 -04:00

184 lines
5.6 KiB
TypeScript

import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { DatabaseObjectDto } from '../dto/database-object.dto';
import { InjectModel } from '@nestjs/mongoose';
import { Game, Player, Team } from '../schemas/game.schema';
import { Document, Model } from 'mongoose';
import { ReadContainerDto, ReadGameDto } from '../dto/read-games.dto';
import { User } from 'src/users/schemas/user.entity';
import { Card } from 'src/cards/schemas/cards.schema';
import { CardRole } from 'src/cards/schemas/cards.types';
import { StartingDeckDto, UpdateGameDto } from '../dto/update-game.dto';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { GameService } from './games.service';
@Injectable()
export class LobbyService {
constructor(
@InjectModel(Game.name) private gameModel: Model<Game>,
@InjectModel(Card.name) private cardModel: Model<Card>,
private readonly gamesService: GameService,
private eventEmitter: EventEmitter2,
) {}
async create(owner: User): Promise<DatabaseObjectDto> {
const createdGame = new this.gameModel();
createdGame.owner = owner;
createdGame.packs = [
'pack1_base_deck',
'pack1_base_necros',
'pack1_base_wild',
'pack1_base_imperial',
'pack1_base_guild',
];
createdGame.teams.push({
players: [{ user: owner } as Player],
} as Team);
const gamedata = await createdGame.save();
const dto = new ReadGameDto(gamedata);
this.eventEmitter.emit('sse.lobby', { type: 'create', ...dto });
return dto;
}
async findAll(): Promise<ReadGameDto[]> {
const games = await this.gameModel.find().exec();
return await Promise.all(
games.map(async (e) => {
return await new ReadGameDto(e);
}),
);
}
async findByOwner(_id: string): Promise<ReadGameDto> {
const game = await this.gameModel.findOne({ owner: _id }).exec();
if (!game) {
return null;
}
return new ReadGameDto(game);
}
async update(game: Document<Game> & Game, updateGameDto: UpdateGameDto) {
game.packs = updateGameDto.packs;
const packs = await this.cardModel.distinct('pack');
if (updateGameDto.packs.every((e) => packs.includes(e))) {
await game.save();
this.eventEmitter.emit('sse.lobby', {
type: 'update',
_id: game._id,
...updateGameDto,
});
this.eventEmitter.emit('sse.game.' + game._id.toHexString(), {
type: 'update',
...updateGameDto,
});
return;
}
throw new HttpException('Pack not found', HttpStatus.NOT_FOUND);
}
async remove(game: Document<Game> & Game) {
this.eventEmitter.emit('sse.lobby', {
_id: game._id,
});
this.eventEmitter.emit('sse.game.' + game._id.toHexString(), {
type: 'delete',
});
return await game.deleteOne();
}
async start(game: Document<Game> & Game) {
const random = Math.floor(Math.random() * game.teams.length);
game.currentTurn = game.teams[random];
await game.save();
game.started = true;
this.eventEmitter.emit('sse.lobby', {
type: 'start',
_id: game._id,
});
this.eventEmitter.emit('sse.game.' + game._id.toHexString(), {
type: 'start',
game: new ReadGameDto(game),
});
let playerIndex = 0;
await Promise.all(
game.teams.map((team) =>
Promise.all(
team.players.map(async (player) => {
player.stack.cards = await this.cardModel
.find({
pack: { $in: game.packs },
role: { $in: [player.class, player.race] },
playerIndex,
})
.exec();
this.eventEmitter.emit('sse.game.' + game._id.toHexString(), {
type: 'populateContainer',
container: new ReadContainerDto(player.stack, true),
});
this.gamesService.shuffleContainer(player.stack, game);
playerIndex++;
}),
),
),
);
game.fireGems.cards = await this.cardModel.find({
pack: { $in: game.packs },
role: CardRole.FIRE_GEM,
});
game.marketStack.cards = await this.cardModel.find({
pack: { $in: game.packs },
role: CardRole.MARKET,
});
this.eventEmitter.emit('sse.game.' + game._id.toHexString(), {
type: 'populateContainer',
container: new ReadContainerDto(game.fireGems),
});
this.eventEmitter.emit('sse.game.' + game._id.toHexString(), {
type: 'populateContainer',
container: new ReadContainerDto(game.marketStack, true),
});
await this.gamesService.shuffleContainer(game.marketStack, game);
await game.save();
}
async changeStartingDeck(
data: StartingDeckDto,
player: Document<Player> & Player,
game: Document<Game> & Game,
) {
const packs = await this.cardModel
.find({ pack: { $in: game.packs } })
.distinct('role');
if (
!Object.values<string>(CardRole).includes(data.class) ||
!Object.values<string>(CardRole).includes(data.race) ||
data.race == CardRole.FIRE_GEM ||
data.race == CardRole.MARKET ||
data.class == CardRole.FIRE_GEM ||
data.class == CardRole.MARKET
) {
throw new HttpException('Invalid race or class', HttpStatus.NOT_FOUND);
}
if (
packs.includes(data.class as CardRole) &&
packs.includes(data.race as CardRole)
) {
player.class = data.class;
player.race = data.race;
await game.save();
this.eventEmitter.emit('sse.game.changeStartingDeck', {
_id: player._id,
...data,
});
return;
}
throw new HttpException('Pack not found', HttpStatus.NOT_FOUND);
}
}