diff --git a/src/game/game.controller.ts b/src/game/game.controller.ts index ec4ed4c..5726cf9 100644 --- a/src/game/game.controller.ts +++ b/src/game/game.controller.ts @@ -1,8 +1,9 @@ -import { Controller, Get, Param, Post } from '@nestjs/common'; +import { Controller, Get, Logger, Param, Post } from '@nestjs/common'; import { GameService } from './game.service'; @Controller('game') export class GameController { + private readonly logger = new Logger(GameController.name); constructor(private gameService: GameService) { } @@ -30,4 +31,10 @@ export class GameController { async playExtraCards() { return this.gameService.playExtraCards(); } + + @Post('simulate-versus') + async SimulateVersus() { + this.logger.verbose('[SimulateVersus] enter'); + return this.gameService.simulateVersus(); + } } diff --git a/src/game/game.service.spec.ts b/src/game/game.service.spec.ts index 9509a9f..bb06bf1 100644 --- a/src/game/game.service.spec.ts +++ b/src/game/game.service.spec.ts @@ -11,6 +11,9 @@ import {ConfigServiceMock} from "../mocks/config-service.mock"; import {SharedService} from "../shared/shared.service"; import {SharedServiceMock} from "../mocks/shared-service.mock"; import {QueryBusMock} from "../mocks/querybus.mock"; +import {Guest} from "../schemas/guest.schema"; +import {GuestsService} from "../guests/guests.service"; +import {GuestsServiceMock} from "../mocks/guests-service.mock"; describe('GameService', () => { let service: GameService; @@ -25,6 +28,7 @@ describe('GameService', () => { { provide: ConfigService, useValue: ConfigServiceMock }, { provide: SharedService, useValue: SharedServiceMock }, { provide: QueryBus, useValue: QueryBusMock }, + { provide: GuestsService, useValue: GuestsServiceMock } ], }).compile(); diff --git a/src/game/game.service.ts b/src/game/game.service.ts index 75c49ca..3a367bd 100644 --- a/src/game/game.service.ts +++ b/src/game/game.service.ts @@ -13,6 +13,7 @@ import { SharedService } from '../shared/shared.service'; import { SocketEvents } from '../shared/events.consts'; import {ConfigService} from "@nestjs/config"; import {gameCards} from "./entities/cards.entities"; +import {GuestsService} from "../guests/guests.service"; @Injectable() export class GameService implements OnApplicationBootstrap{ @@ -26,6 +27,7 @@ export class GameService implements OnApplicationBootstrap{ private sharedService: SharedService, private commandBus: CommandBus, private queryBus: QueryBus, + private guestService: GuestsService, ) { } @@ -113,4 +115,24 @@ export class GameService implements OnApplicationBootstrap{ cardInstance.setupHandlers(this.eventBus, this.commandBus, this.queryBus); }) } + + async simulateVersus() { + const guests = (await this.guestService.findAll()).slice(0,2).map((guest) => { + return { + id: guest.telegramId, + name: guest.name, + } + }); + if(guests.length < 2) { + throw new Error("Can't simulate, in db less than 2 players") + } + await this.beginVersus(guests[0].id, guests[1].id); + } + + async beginVersus(player1: number, player2: number) { + this.sharedService.sendSocketNotificationToAllClients( + SocketEvents.BEGIN_VERSUS, + { player1, player2 } + ) + } } diff --git a/src/guests/guest.types.d.ts b/src/guests/guest.types.d.ts new file mode 100644 index 0000000..894e19e --- /dev/null +++ b/src/guests/guest.types.d.ts @@ -0,0 +1,5 @@ +export interface GuestNamesInCases { + SubjectiveCase: string; + AccusativeCase: string; + GenitiveCase: string; +} \ No newline at end of file diff --git a/src/guests/guests.service.ts b/src/guests/guests.service.ts index 650f83a..dfe0cc0 100644 --- a/src/guests/guests.service.ts +++ b/src/guests/guests.service.ts @@ -1,7 +1,7 @@ import {Inject, Injectable, Logger} from '@nestjs/common'; import {InjectModel} from '@nestjs/mongoose'; import {Guest, GuestDocument} from '../schemas/guest.schema'; -import {Model} from 'mongoose'; +import {Document, Model} from 'mongoose'; import {CreateGuestDto} from './dto/create-guest.dto'; import {QuestionDto} from '../quiz/dto/question.dto'; import {Messages} from '../messaging/tg.text'; @@ -27,6 +27,7 @@ import {DebuffsConsts} from "../game/entities/debuffs.consts"; import {VoiceService} from "../voice/voice.service"; import {screpaDictManyInvalidAnswersDict} from "../voice/dicts/screpa-dict-many-invalid-answers.dict"; import {GuestPropertiesConsts} from "../schemas/properties.consts"; +import {GuestNamesInCases} from "./guest.types"; @Injectable() export class GuestsService { @@ -312,6 +313,15 @@ export class GuestsService { await this.guestModel.updateMany({}, { prizeChance: 0 }); } + async getGuestNameInCases(telegramId: number): Promise { + const guest = await this.findById(telegramId); + return { + SubjectiveCase: guest.get(StringHelper.getPropertyName(GuestPropertiesConsts.NameSubjectiveCase)), + AccusativeCase: guest.get(StringHelper.getPropertyName(GuestPropertiesConsts.NameAccusativeCase)), + GenitiveCase: guest.get(StringHelper.getPropertyName(GuestPropertiesConsts.NameGenitiveCase)) + } + } + async incrementInvalidAnswersCount(tId: number) { this.logger.verbose(`Increment invalid answers in the row for ${tId}`); const guest = await this.findById(tId); diff --git a/src/quiz/quiz.controller.ts b/src/quiz/quiz.controller.ts index 652de1f..5c251be 100644 --- a/src/quiz/quiz.controller.ts +++ b/src/quiz/quiz.controller.ts @@ -54,6 +54,6 @@ export class QuizController { @Get('endgame-extrapoints') async endgameExtrapoints() { - return await this.quizService.addEndgamePoints(); + return await this.quizService.calculateEndgamePoints(); } } diff --git a/src/quiz/quiz.service.ts b/src/quiz/quiz.service.ts index 208221f..d4f93eb 100644 --- a/src/quiz/quiz.service.ts +++ b/src/quiz/quiz.service.ts @@ -18,6 +18,7 @@ import {IncreasePlayerWinningRateCommand} from "../game/commands/increase-player import {IncreasePlayerScoreCommand} from "../guests/command/increase-player-score.command"; import {FeatureflagService} from "../featureflag/featureflag.service"; import {FeatureFlagsConsts} from "../Consts/FeatureFlags.consts"; +import {QuizEndGameResults} from "./quiz.types"; @Injectable({ scope: Scope.TRANSIENT }) export class QuizService { @@ -167,7 +168,7 @@ export class QuizService { await this.commandBus.execute(new CreateNewQueueItemCommand(targetUser, GameQueueTypes.showresults)); } - public async addEndgamePoints() { + public async calculateEndgamePoints(): Promise { const maxInvalidAnswersPromise = this.guestService.getModel().find({}).sort({ ['invalidAnswers']: 'desc'}).exec(); const maxRewardsPromise = this.guestService.getModel().find({}).sort({['rewardsReceived']: "desc"}).exec(); const maxPenaltiesPromise = this.guestService.getModel().find({}).sort({['penaltiesReceived']: 'desc'}).exec(); diff --git a/src/quiz/quiz.types.d.ts b/src/quiz/quiz.types.d.ts new file mode 100644 index 0000000..69f34b4 --- /dev/null +++ b/src/quiz/quiz.types.d.ts @@ -0,0 +1,11 @@ +export interface QuizEndGameResultsDetails { + id: number; + count: number; + name: string; +} + +export interface QuizEndGameResults { + maxInvalidAnswers: QuizEndGameResultsDetails; + maxRewards: QuizEndGameResultsDetails; + maxPenalties: QuizEndGameResultsDetails; +} \ No newline at end of file diff --git a/src/scheduler/scheduler.service.spec.ts b/src/scheduler/scheduler.service.spec.ts index 3a38d6e..5329357 100644 --- a/src/scheduler/scheduler.service.spec.ts +++ b/src/scheduler/scheduler.service.spec.ts @@ -10,6 +10,10 @@ import {SharedService} from "../shared/shared.service"; import {SharedServiceMock} from "../mocks/shared-service.mock"; import {FeatureflagService} from "../featureflag/featureflag.service"; import {FeatureflagServiceMock} from "../mocks/featureflag-service.mock"; +import {GuestsService} from "../guests/guests.service"; +import {GuestsServiceMock} from "../mocks/guests-service.mock"; +import {CommandBus} from "@nestjs/cqrs"; +import {CommandbusMock} from "../mocks/commandbus.mock"; describe('SchedulerService', () => { @@ -26,7 +30,9 @@ describe('SchedulerService', () => { { provide: StateService, useValue: StateServiceMock }, { provide: QuizService, useValue: QuizServiceMock }, { provide: SharedService, useValue: SharedServiceMock }, - { provide: FeatureflagService, useValue: FeatureflagServiceMock } + { provide: FeatureflagService, useValue: FeatureflagServiceMock }, + { provide: CommandBus, useValue: CommandbusMock }, + { provide: GuestsService, useValue: GuestsServiceMock }, ], }).compile(); diff --git a/src/scheduler/scheduler.service.ts b/src/scheduler/scheduler.service.ts index fcea24e..175a4a5 100644 --- a/src/scheduler/scheduler.service.ts +++ b/src/scheduler/scheduler.service.ts @@ -1,11 +1,15 @@ -import { Injectable, Logger } from '@nestjs/common'; -import { Cron } from '@nestjs/schedule'; -import { StateService } from '../state/state.service'; -import { QuizService } from '../quiz/quiz.service'; -import { GiftsService } from '../gifts/gifts.service'; -import { SharedService } from '../shared/shared.service'; +import {Injectable, Logger} from '@nestjs/common'; +import {Cron} from '@nestjs/schedule'; +import {StateService} from '../state/state.service'; +import {QuizService} from '../quiz/quiz.service'; +import {GiftsService} from '../gifts/gifts.service'; +import {SharedService} from '../shared/shared.service'; import {FeatureflagService} from "../featureflag/featureflag.service"; import {FeatureFlagsConsts} from "../Consts/FeatureFlags.consts"; +import {CommandBus} from "@nestjs/cqrs"; +import {EndgameDict} from "../voice/dicts/endgame.dict"; +import {CreateNewQueueItemCommand} from "../game/commands/create-new-queue-item.command"; +import {GameQueueTypes} from "../schemas/game-queue.schema"; @Injectable() export class SchedulerService { @@ -19,6 +23,7 @@ export class SchedulerService { private quizService: QuizService, private sharedService: SharedService, private featureFlagService: FeatureflagService, + private commandBus: CommandBus, ) {} @Cron('* * * * *') @@ -26,6 +31,34 @@ export class SchedulerService { await this.updateState(); } + + + async finishGame() { + if(await this.featureFlagService.getFeatureFlag(FeatureFlagsConsts.EnableEndgamePoints)) { + this.logger.verbose(`Feature flag ${FeatureFlagsConsts.EnableEndgamePoints} is enabled`); + const endgamePoints = await this.quizService.calculateEndgamePoints(); + await Promise.all([ + this.commandBus.execute( + new CreateNewQueueItemCommand(endgamePoints.maxInvalidAnswers.id, + GameQueueTypes.extra_points, + EndgameDict.maxAmountOfInvalidQuestions)), + new CreateNewQueueItemCommand(endgamePoints.maxPenalties.id, + GameQueueTypes.extra_points, + EndgameDict.maxPenalties), + new CreateNewQueueItemCommand(endgamePoints.maxRewards.id, + GameQueueTypes.extra_points, + EndgameDict.maxAmountOfRewards) + ]); + } else { + const state = await this.stateService.setState('main', 'finish'); + this.sharedService.sendSocketNotificationToAllClients( + 'state_changed', + state, + ); + this.logger.warn(`Gifts is ended, finishing game`); + } + } + private async updateState() { this.state = (await this.stateService.getState('main')).value; this.logger.verbose(`Game state is: ${this.state}`); @@ -34,15 +67,7 @@ export class SchedulerService { async gameStatus() { const giftsLeft = await this.giftsService.getRemainingPrizeCount(); if (giftsLeft === 0) { - if(await this.featureFlagService.getFeatureFlag(FeatureFlagsConsts.EnableEndgamePoints)) { - this.logger.verbose(`Feature flag ${FeatureFlagsConsts.EnableEndgamePoints} is enabled`); - } - const state = await this.stateService.setState('main', 'finish'); - this.sharedService.sendSocketNotificationToAllClients( - 'state_changed', - state, - ); - this.logger.warn(`Gifts is ended, finishing game`); + await this.finishGame(); } const questionsLeft = await this.quizService.getRemainQuestionCount(); this.logger.verbose( diff --git a/src/schemas/game-queue.schema.ts b/src/schemas/game-queue.schema.ts index fc32b04..15ed27c 100644 --- a/src/schemas/game-queue.schema.ts +++ b/src/schemas/game-queue.schema.ts @@ -8,6 +8,7 @@ export enum GameQueueTypes { playExtraCard = 'play_extra_card', screpaAnounce = 'screpa', showresults = 'show_results', + extra_points = 'extra_points', } export type GameQueueDocument = GameQueue & Document; diff --git a/src/shared/events.consts.ts b/src/shared/events.consts.ts index 4806418..1823fe5 100644 --- a/src/shared/events.consts.ts +++ b/src/shared/events.consts.ts @@ -13,4 +13,5 @@ export enum SocketEvents { GAME_RESUMED = 'game_resumed', NOTIFICATION = 'notification', FEATURE_FLAG_CHANGED = 'feature_flag_changed', + BEGIN_VERSUS = 'begin_versus', } diff --git a/src/voice/dicts/endgame.dict.ts b/src/voice/dicts/endgame.dict.ts new file mode 100644 index 0000000..d0cc39d --- /dev/null +++ b/src/voice/dicts/endgame.dict.ts @@ -0,0 +1,6 @@ + +export class EndgameDict { + static maxAmountOfInvalidQuestions = "За самое большое количество неправильных ответов, 2 балла получает %GenitiveCase%"; + static maxAmountOfRewards ="За самое большое количество полученных призов %GenitiveCase% получает минус два балла"; + static maxPenalties = "За самое большое количество наказаний %GenitiveCase% получает 3 балла"; +} \ No newline at end of file diff --git a/src/voice/voice.controller.ts b/src/voice/voice.controller.ts index 7382ab5..32452a3 100644 --- a/src/voice/voice.controller.ts +++ b/src/voice/voice.controller.ts @@ -4,7 +4,6 @@ import { TtsRequestDto, TtsRequestWithVars } from './models/TtsRequestDto'; import { invalidPrefixDict } from './dicts/invalid-prefix.dict'; import { validPrefixDict } from './dicts/valid-prefix.dict'; import * as translit from 'latin-to-cyrillic'; -import {ConfigService} from "@nestjs/config"; import {FeatureflagService} from "../featureflag/featureflag.service"; import {FeatureFlagsConsts} from "../Consts/FeatureFlags.consts"; @Controller('voice') @@ -22,7 +21,6 @@ export class VoiceController { } - @Get('ssml') @Header('content-type', 'audio/opus') @Header('content-disposition', 'inline') @@ -33,7 +31,6 @@ export class VoiceController { } else { return new NotFoundException('Voice disabled'); } - } @Get('tts') diff --git a/src/voice/voice.service.ts b/src/voice/voice.service.ts index 45098db..0a662c5 100644 --- a/src/voice/voice.service.ts +++ b/src/voice/voice.service.ts @@ -30,7 +30,6 @@ export class VoiceService { } this.logger.verbose(`Result is: ${template}`); // eslint-disable-next-line @typescript-eslint/no-var-requires - template = translit(template); return template; }