diff --git a/src/game/comand-handlers/proceed-game-queue-command.handler.ts b/src/game/comand-handlers/proceed-game-queue-command.handler.ts index 28dcd2c..1cd5497 100644 --- a/src/game/comand-handlers/proceed-game-queue-command.handler.ts +++ b/src/game/comand-handlers/proceed-game-queue-command.handler.ts @@ -27,7 +27,7 @@ export class GameProceedGameQueueCommandHandler return this.cmdBus.execute(new NextQuestionCommand()); } this.sharedService.notifyAllClients(ClientNotificationType.GameQueueItem, { - _id: item.id, + _id: item._id, completed: item.completed, target: item.target, type: item.type, diff --git a/src/game/entities/cards.entities.ts b/src/game/entities/cards.entities.ts index 5ee0af4..2366170 100644 --- a/src/game/entities/cards.entities.ts +++ b/src/game/entities/cards.entities.ts @@ -250,7 +250,7 @@ export class BanPlayer extends GameCard { async handle() { await this.commandBus.execute( - new SelectTargetPlayerCommand(this.telegramId, DebuffsConsts.bannedFor, 2,false) + new SelectTargetPlayerCommand(this.telegramId, DebuffsConsts.bannedFor, getRandomInt(2,3), false) ) await this.queryBus.execute(new FilterGuestsWithPropertyQuery(null,null,null)); this.eventBus.subscribe((data) =>{ diff --git a/src/game/events/state-changed.event.ts b/src/game/events/state-changed.event.ts new file mode 100644 index 0000000..76acc40 --- /dev/null +++ b/src/game/events/state-changed.event.ts @@ -0,0 +1,4 @@ +export class StateChangedEvent { + constructor(state: string) { + } +} \ No newline at end of file diff --git a/src/game/game.service.ts b/src/game/game.service.ts index 0092070..abd9bba 100644 --- a/src/game/game.service.ts +++ b/src/game/game.service.ts @@ -52,7 +52,26 @@ export class GameService implements OnApplicationBootstrap{ } async getGameQueueItem() { - return this.gameQueueModel.findOne({ completed: false }).exec(); + const item = await this.gameQueueModel.aggregate([ + { + $match: { completed: false } + }, + { + $addFields: { + priority: { + $cond: [{ $eq: ["$type", "versus"] }, 1, 0] + } + } + }, + { + $sort: { priority: -1 } + }, + { + $limit: 1 + } + ]).exec(); + console.log(item[0]); + return item[0]; } async markQueueAsCompleted(id: string| null) { diff --git a/src/game/versus/versus.service.ts b/src/game/versus/versus.service.ts index a4dbcb4..782e0db 100644 --- a/src/game/versus/versus.service.ts +++ b/src/game/versus/versus.service.ts @@ -13,6 +13,8 @@ import {GuestPropertyNamesConsts} from "../../Consts/guest-property-names.consts import {SetGuestPropertyCommand} from "../../guests/command/set-guest-property.command"; import {IVersusBeginSocketEvent, IVersusEndSocketEvent} from "../../Consts/types"; import {ClientNotificationType} from "../../socket/socket.gateway"; +import {CreateNewQueueItemCommand} from "../commands/create-new-queue-item.command"; +import {GameQueueTypes} from "../../schemas/game-queue.schema"; @Injectable() export class VersusService { @@ -42,6 +44,7 @@ export class VersusService { async beginVersus(player1: number, player2: number) { const [p1data,p2data] = await Promise.all([this.guestService.findById(player1), this.guestService.findById(player2)]); + await this.cmdBus.execute(new CreateNewQueueItemCommand(player1, GameQueueTypes.versus)); await this.sharedService.setConfig(VersusService.configKeyCurrentAction, JSON.stringify({ action:'versus', data: { diff --git a/src/guests/guests.service.ts b/src/guests/guests.service.ts index 97fa427..959f713 100644 --- a/src/guests/guests.service.ts +++ b/src/guests/guests.service.ts @@ -76,6 +76,9 @@ export class GuestsService { async findById(id: number) { const result = await this.guestModel.findOne({ telegramId: id }).exec(); + if(!result) { + return null; + } delete result.photo; return result; } diff --git a/src/quiz/event-handlers/state-changed-event.handler.ts b/src/quiz/event-handlers/state-changed-event.handler.ts new file mode 100644 index 0000000..e8cb84c --- /dev/null +++ b/src/quiz/event-handlers/state-changed-event.handler.ts @@ -0,0 +1,17 @@ +import {EventsHandler, IEventHandler} from "@nestjs/cqrs"; +import {StateChangedEvent} from "../../game/events/state-changed.event"; +import {QuizService} from "../quiz.service"; +import {Logger} from "@nestjs/common"; + +@EventsHandler(StateChangedEvent) +export class StateChangedEventHandler implements IEventHandler { + logger = new Logger(StateChangedEventHandler.name); + constructor(private quizService: QuizService) { + } + + async handle(event: StateChangedEvent) { + this.logger.verbose(`[StateChangedEventHandler] enter, event: ${event}}`) + await this.quizService.calculateEndgamePoints(); + } + +} \ No newline at end of file diff --git a/src/quiz/quiz.controller.ts b/src/quiz/quiz.controller.ts index 10818be..554b603 100644 --- a/src/quiz/quiz.controller.ts +++ b/src/quiz/quiz.controller.ts @@ -26,6 +26,11 @@ export class QuizController { return this.quizService.proceedWithGame(); } + @Post('timeout') + async Timeout() { + return await this.quizService.questionTimeout(); + } + @Post('questions') async postQuestion(@Body() questionDto: QuestionDto[]) { return await this.quizService.populateQuestions(questionDto); diff --git a/src/quiz/quiz.module.ts b/src/quiz/quiz.module.ts index 3975216..e3ed269 100644 --- a/src/quiz/quiz.module.ts +++ b/src/quiz/quiz.module.ts @@ -12,12 +12,17 @@ import { MarkQuestionsAsUnansweredCommandHandler } from './command-handlers/mark import { PenaltyModule } from '../penalty/penalty.module'; import {ConfigModule, ConfigService} from "@nestjs/config"; import {Config, ConfigSchema} from "../schemas/config.schema"; +import {StateChangedEventHandler} from "./event-handlers/state-changed-event.handler"; const cmdHandlers = [ GameNextQuestionCommandHandler, MarkQuestionsAsUnansweredCommandHandler, ]; +const eventHandlers = [ + StateChangedEventHandler +] + @Global() @Module({ imports: [ @@ -33,6 +38,6 @@ const cmdHandlers = [ ], controllers: [QuizController], exports: [QuizService], - providers: [QuizService,ConfigService, ...cmdHandlers], + providers: [QuizService,ConfigService, ...cmdHandlers, ...eventHandlers], }) export class QuizModule {} diff --git a/src/quiz/quiz.service.ts b/src/quiz/quiz.service.ts index 96c27e2..21be7bb 100644 --- a/src/quiz/quiz.service.ts +++ b/src/quiz/quiz.service.ts @@ -60,6 +60,9 @@ export class QuizService { ); // check that answer exist const shortAnswers = question.answers.map((answer) => answer.substring(0,50)); + if(question.countdownFinished) { + return; + } const shortValidAnswer = question.valid.substring(0,50); if(shortAnswers.indexOf(answer) === -1) { this.logger.warn(`[validateAnswer] this question is not on game now`); @@ -124,7 +127,7 @@ export class QuizService { return false; } const diff = Math.abs(new Date(answers[0].time).getTime() - new Date(answers[1].time).getTime()) / 1000; - return diff <= 5; + return diff <= 1; } async calculateScore() { @@ -148,7 +151,7 @@ export class QuizService { const winner = sortedAnswers.find((answer) => answer.valid); let targetUser = 0; if(winner) { - const totalWinningScore = 80; + const totalWinningScore = 50; sortedAnswers.filter(x => x.valid).forEach((answer) => { this.logger.debug(`Giving 1 point to all who answered right`); this.commandBus.execute(new IncreasePlayerWinningRateCommand(answer.user, @@ -165,7 +168,7 @@ export class QuizService { )); } } - await this.commandBus.execute(new IncreasePlayerWinningRateCommand(sortedAnswers[0].user, 15)); + await this.commandBus.execute(new IncreasePlayerWinningRateCommand(sortedAnswers[0].user, 5)); this.logger.debug(`Giving 1 point to first`); await this.commandBus.execute(new IncreasePlayerScoreCommand(winner.user,1)); targetUser = winner.user; @@ -214,6 +217,9 @@ export class QuizService { } } await this.sharedService.setConfig('endgame-points', JSON.stringify(result)); + await this.commandBus.execute(new IncreasePlayerScoreCommand(result.maxInvalidAnswers.id, 2)); + await this.commandBus.execute(new IncreasePlayerScoreCommand(result.maxPenalties.id, 2)); + await this.commandBus.execute(new IncreasePlayerScoreCommand(result.maxRewards.id, -2)); return result; } @@ -340,4 +346,11 @@ export class QuizService { const res = await this.sharedService.getConfig('endgame-points'); return JSON.parse(res.value); } + + async questionTimeout() { + const question = await this.get(); + question.countdownFinished = true; + await question.save(); + return question; + } } diff --git a/src/schemas/game-queue.schema.ts b/src/schemas/game-queue.schema.ts index 15ed27c..80107c2 100644 --- a/src/schemas/game-queue.schema.ts +++ b/src/schemas/game-queue.schema.ts @@ -9,6 +9,7 @@ export enum GameQueueTypes { screpaAnounce = 'screpa', showresults = 'show_results', extra_points = 'extra_points', + versus = 'versus', } export type GameQueueDocument = GameQueue & Document; diff --git a/src/schemas/question.schema.ts b/src/schemas/question.schema.ts index 2f23742..3cb1762 100644 --- a/src/schemas/question.schema.ts +++ b/src/schemas/question.schema.ts @@ -31,5 +31,7 @@ export class Question { userAnswers: QuestionAnswer[]; @Prop({ default: false }) scoreCalculated: boolean; + @Prop({ default: false}) + countdownFinished: boolean; } export const QuestionSchema = SchemaFactory.createForClass(Question); diff --git a/src/state/state.controller.ts b/src/state/state.controller.ts index 1ad04e7..dcd2e75 100644 --- a/src/state/state.controller.ts +++ b/src/state/state.controller.ts @@ -38,16 +38,16 @@ export class StateController { if (setStateDto.value === 'quiz') { this.eventBus.publish(new GameStartedEvent()); } else if(setStateDto.value === 'onboarding') { - this.telegramService.send( - { cmd: CommandsConsts.SetCommands }, - [ - { command: 'start', description: 'главное меню'}, - { command: 'cards', description: 'сыграть карту'}, - { command: 'question', description: 'вернутся к вопросу'} - ] - ).subscribe(() => { - this.logger.verbose('Bot commands updated'); - }); + // this.telegramService.send( + // { cmd: CommandsConsts.SetCommands }, + // [ + // { command: 'start', description: 'главное меню'}, + // { command: 'cards', description: 'сыграть карту'}, + // { command: 'question', description: 'вернутся к вопросу'} + // ] + // ).subscribe(() => { + // this.logger.verbose('Bot commands updated'); + // }); } else { this.logger.verbose('reset commands'); this.telegramService.emit({ cmd: CommandsConsts.ResetCommands }, {}); diff --git a/src/state/state.service.ts b/src/state/state.service.ts index 783e24d..c6937c2 100644 --- a/src/state/state.service.ts +++ b/src/state/state.service.ts @@ -5,6 +5,7 @@ import { Model } from 'mongoose'; import { EventBus } from '@nestjs/cqrs'; import { PrepareGameEvent } from '../game/events/prepare-game.event'; import {IStateInfo} from "../Consts/types"; +import {StateChangedEvent} from "../game/events/state-changed.event"; interface StateDTO { name: string; @@ -35,6 +36,8 @@ export class StateService { if (newValue === 'onboarding') { this.eventBus.publish(new PrepareGameEvent()); } + this.eventBus.publish(new StateChangedEvent(newValue)); + const stateEntity = await this.getState(name); stateEntity.value = newValue; await stateEntity.save();