Files
webapp-back/src/games/services/games.service.ts
T

135 lines
3.8 KiB
TypeScript

import {
forwardRef,
HttpException,
HttpStatus,
Inject,
Injectable,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Game } from '../entities/game.entity';
import { Repository } from 'typeorm';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { Player } from '../entities/player.entity';
import { User } from 'src/users/entities/user.entity';
import {
GameEndTurnEvent,
GameMessageDeleteEvent,
GameMessageEvent,
GameStartEvent,
} from 'events/game.events';
import random from 'random';
import { Message } from '../entities/message.entity';
import { WordService } from 'src/word/word.service';
@Injectable()
export class GameService {
constructor(
@InjectRepository(Game) private gameRepository: Repository<Game>,
@InjectRepository(Message) private messageResporitory: Repository<Message>,
@InjectRepository(Player) private playerRepository: Repository<Player>,
private readonly wordService: WordService,
private eventEmitter: EventEmitter2,
) {}
async start(game: Game) {
const rng = random.clone(game.seed);
game.started = true;
game.currentPlayer = rng.choice(game.players);
const words = await this.getShuffledWordList(game);
game.currentWord = words[0];
await this.gameRepository.save(game);
this.eventEmitter.emit(
'sse.game.' + game.id,
new GameStartEvent(game.currentPlayer),
);
}
async postMessage(game: Game, author: Player, value: string) {
const message = this.messageResporitory.create();
message.game = Promise.resolve(game);
if (
value.toLowerCase() == game.currentWord.value.toLowerCase() &&
author.id != game.currentPlayer.id
) {
message.value = author.userId;
author.hasGuessed = true;
author.score++;
game.currentPlayer.score++;
await this.playerRepository.save([author, game.currentPlayer]);
} else {
message.author = author;
message.value = value;
}
await this.messageResporitory.save(message);
this.eventEmitter.emit(
'sse.game.' + game.id,
new GameMessageEvent(message),
);
if (game.messages.length > 3) {
await this.deleteMessage(game, game.messages[0]);
}
if (
game.players
.filter((p) => p.id != game.currentPlayer.id)
.every((p) => p.hasGuessed)
) {
await this.endTurn(game);
}
}
private async deleteMessage(game: Game, message: Message) {
const oldMessageId = message.id;
await this.messageResporitory.remove(message);
this.eventEmitter.emit(
'sse.game.' + game.id,
new GameMessageDeleteEvent(oldMessageId),
);
}
async endTurn(game: Game) {
const smartPlayers = game.players.filter((p) => p.hasGuessed);
smartPlayers.forEach((p) => (p.hasGuessed = false));
const wordList = await this.getShuffledWordList(game);
game.turn++;
game.currentWord = wordList[game.turn % wordList.length];
const playerIndex = game.players.findIndex(
(p) => p.userId == game.currentPlayer.userId,
);
game.currentPlayer = game.players[(playerIndex + 1) % game.players.length];
// await this.currentConceptReporitory.remove(game.currentConcept)
await this.gameRepository.save(game);
await this.playerRepository.save(smartPlayers);
await this.messageResporitory.delete({ game });
this.eventEmitter.emit(
'sse.game.' + game.id,
new GameEndTurnEvent(game.currentPlayer),
);
}
/**
* Shuffles the word list using a per-game seeded rng
*/
async getShuffledWordList(game: Game) {
const rng = random.clone(game.seed);
const words = await this.wordService.listActive();
return words
.map((value) => ({ value, sort: rng.float() }))
.sort((a, b) => a.sort - b.sort)
.map(({ value }) => value);
}
async end(game: Game, winner: Player) {
throw Error('Not Implemented');
}
}