import { QuizAnswerStateEnum } from './quiz-answer-state.enum'; import {CommandBus, EventBus, ofType, QueryBus} from '@nestjs/cqrs'; import {Injectable, Logger} from '@nestjs/common'; import { IncreasePlayerWinningRateCommand } from '../commands/increase-player-winning-rate.command'; import { CreateNewQueueItemCommand } from '../commands/create-new-queue-item.command'; import { GameQueueTypes } from '../../schemas/game-queue.schema'; import { NotifyCardOnScreenCommand } from '../commands/notify-card-on-screen-command'; import { SendToastCommand } from '../commands/send-toast.command'; import { getRandomInt } from '../../helpers/rand-number'; import { GiveOutAPrizeCommand } from '../commands/give-out-a-prize.command'; import {SelectTargetPlayerCommand} from "../commands/select-target-player.command"; import {DebuffsConsts} from "./debuffs.consts"; import {NextQuestionEvent} from "../events/next-question.event"; import {FilterGuestsWithPropertyQuery} from "../../guests/queries/filterguestswithproperty.query"; import {DebuffCardPlayedEvent} from "../events/debuff-card-played.event"; import {filter} from "rxjs"; import {SetGuestPropertyCommand} from "../../guests/command/set-guest-property.command"; import {StringHelper} from "../../helpers/stringhelper"; import {GetGuestQuery} from "../../guests/queries/getguest.query"; import {CardsSetChangedEvent} from "../events/cards-events/cards-set-changed.event"; import {GuestPropertiesConsts} from "../../schemas/properties.consts"; import {BeginVersusCommand} from "../commands/begin-versus.command"; import {CheckIfAnotherVersusInProgressQuery} from "../queries/check-if-another-versus-in-progress.query"; export interface IGameCard { setupHandlers(eventBus: EventBus, commandBus: CommandBus, queryBus: QueryBus): void; } export class GameCard implements IGameCard{ protected readonly logger = new Logger(GameCard.name); protected commandBus: CommandBus; protected eventBus: EventBus; protected queryBus: QueryBus; protected telegramId: number; protected destinationTelegramId: number; public handlers: { event: any, commands: any[]}[] = []; name: string; description: string; protected emoji: string; public dealOnStart = false; chance = 0; getEmoji() { return this.emoji; } setup(eb: EventBus, cb: CommandBus, qb: QueryBus, tId: number, destTId: number) { this.eventBus = eb; this.commandBus = cb; this.telegramId = tId; this.destinationTelegramId = destTId; this.queryBus = qb; } async handle() { this.logger.verbose(`Card has no handler`); } mightBePlayed: QuizAnswerStateEnum; setupHandlers(eventBus: EventBus, commandBus: CommandBus, queryBus: QueryBus) { } } export class DoubleTreasureCard extends GameCard { name = DoubleTreasureCard.name; description = 'Удвоить приз'; chance = 4; emoji = '💰'; mightBePlayed = QuizAnswerStateEnum.playerGettingReward; async handle(): Promise { await this.commandBus.execute( new NotifyCardOnScreenCommand(this.telegramId, this), ); await this.commandBus.execute( new GiveOutAPrizeCommand(this.telegramId), ); const userSrc = await this.queryBus.execute(new GetGuestQuery(this.telegramId)); const subjcaseFrom = userSrc.get(StringHelper.getPropertyName(GuestPropertiesConsts.NameSubjectiveCase)); const message = `${subjcaseFrom} решает удвоить приз!`; await this.commandBus.execute(new SendToastCommand(message, 8000)); } } export class StolePrizeCard extends GameCard { name = StolePrizeCard.name; description = 'Украсть приз'; chance = 15; emoji = '🥷🏽'; mightBePlayed = QuizAnswerStateEnum.someoneGettingReward; async handle(): Promise { this.logger.verbose(`StolePrize from player ${this.telegramId} to player ${this.destinationTelegramId}`); await this.commandBus.execute( new NotifyCardOnScreenCommand(this.telegramId, this), ); const userSrc = await this.queryBus.execute(new GetGuestQuery(this.telegramId)); const userDst = await this.queryBus.execute(new GetGuestQuery(this.destinationTelegramId)); const subjcaseFrom = userSrc.get(StringHelper.getPropertyName(GuestPropertiesConsts.NameSubjectiveCase)); const genitiveTo = userDst.get(StringHelper.getPropertyName(GuestPropertiesConsts.NameGenitiveCase)); const message = `${subjcaseFrom} крадет приз у ${genitiveTo}`; await this.commandBus.execute(new SendToastCommand(message, 8000)); } } export class ShitCard extends GameCard { name = ShitCard.name; description = 'Говнокарта'; chance = 50; emoji = '💩'; mightBePlayed = QuizAnswerStateEnum.someoneAnsweredCorrectly; async handle(): Promise { this.logger.verbose(`Shit card from player ${this.telegramId} to player ${this.destinationTelegramId}`); await this.commandBus.execute( new NotifyCardOnScreenCommand(this.telegramId, this), ); await this.commandBus.execute( new CreateNewQueueItemCommand( this.destinationTelegramId, GameQueueTypes.additionalQuestion, ), ); const userSrc = await this.queryBus.execute(new GetGuestQuery(this.telegramId)); const userDst = await this.queryBus.execute(new GetGuestQuery(this.destinationTelegramId)); const subjcaseFrom = userSrc.get(StringHelper.getPropertyName(GuestPropertiesConsts.NameSubjectiveCase)); const accusativeTo = userDst.get(StringHelper.getPropertyName(GuestPropertiesConsts.NameAccusativeCase)); const message = `${subjcaseFrom} кидает говно-карту в ${accusativeTo}`; await this.commandBus.execute(new SendToastCommand(message, 8000)); } } export class LuckyCard extends GameCard { name = LuckyCard.name; description = 'Лаки-карта'; chance = 32; mightBePlayed = QuizAnswerStateEnum.playerAnsweredCorrectly; emoji = '🍀'; async handle() { this.logger.verbose(`Handling card`); const user = await this.queryBus.execute(new GetGuestQuery(this.telegramId)); const subjcase = user.get(StringHelper.getPropertyName(GuestPropertiesConsts.NameSubjectiveCase)); const message = `${subjcase} использует лаки карту`; this.logger.verbose(`message: ${message}`); await this.commandBus.execute(new SendToastCommand(message, 8000)); await this.commandBus.execute( new NotifyCardOnScreenCommand(this.telegramId, this), ); await this.commandBus.execute( new IncreasePlayerWinningRateCommand( this.telegramId, getRandomInt(8, 20), ), ); } } export class AvoidPenaltyCard extends GameCard { dealOnStart = true; name = AvoidPenaltyCard.name; description = 'Избежать наказание'; chance = 25; emoji = '🏃‍'; mightBePlayed = QuizAnswerStateEnum.playerGotPenalty; async handle() { const user = await this.queryBus.execute(new GetGuestQuery(this.telegramId)); const subjcase = user.get(StringHelper.getPropertyName(GuestPropertiesConsts.NameSubjectiveCase)); const message = `${subjcase} избегает наказания`; this.logger.verbose(`message: ${message}`); await this.commandBus.execute(new SendToastCommand(message, 8000)); await this.commandBus.execute( new NotifyCardOnScreenCommand(this.telegramId, this), ); } } @Injectable() export class VersusCard extends GameCard { dealOnStart = true; name = VersusCard.name; chance = 10; emoji = '🆚'; description = 'Поединок'; mightBePlayed = QuizAnswerStateEnum.betweenRounds; async setupHandlers(eventBus: EventBus, commandBus: CommandBus, queryBus: QueryBus) { super.setupHandlers(eventBus, commandBus, queryBus); eventBus.pipe( ofType(DebuffCardPlayedEvent), filter(x => x.debufName == DebuffsConsts.versus)) .subscribe(async (r) =>{ const versusInProgress = await queryBus.execute(new CheckIfAnotherVersusInProgressQuery()); this.logger.verbose(`versusInProgress ${versusInProgress}`); if(versusInProgress) { this.logger.warn(`another versus in progress`); return; } const destUser = await queryBus.execute(new GetGuestQuery(r.dest)) const sourceUser = await queryBus.execute(new GetGuestQuery(r.from)); await commandBus.execute(new BeginVersusCommand(sourceUser.telegramId, destUser.telegramId)); }); } async handle() { await this.commandBus.execute( new SelectTargetPlayerCommand(this.telegramId, DebuffsConsts.versus, 0, false) ) await this.queryBus.execute(new FilterGuestsWithPropertyQuery(null,null,null)); this.eventBus.subscribe((data) =>{ this.logger.verbose(`Response from cmdBus: ${data}`); }); } } @Injectable() export class BanPlayer extends GameCard { dealOnStart = true; name = BanPlayer.name; description = 'Забанить игрока'; chance = 10; emoji = '🚷'; mightBePlayed = QuizAnswerStateEnum.betweenRounds; async setupHandlers(eventBus: EventBus, commandBus: CommandBus, queryBus: QueryBus) { super.setupHandlers(eventBus, commandBus, queryBus); eventBus.pipe(ofType(DebuffCardPlayedEvent),filter(x => x.debufName == DebuffsConsts.bannedFor)).subscribe(async (r) => { const destUser = await queryBus.execute(new GetGuestQuery(r.dest)) const sourceUser = await queryBus.execute(new GetGuestQuery(r.from)); const subjectiveSource = sourceUser.get(StringHelper.getPropertyName(GuestPropertiesConsts.NameSubjectiveCase)); const accusativeDest = destUser.get(StringHelper.getPropertyName(GuestPropertiesConsts.NameAccusativeCase)); const message = `Игрок ${subjectiveSource} забанил ${accusativeDest} `; await commandBus.execute(new SetGuestPropertyCommand(r.dest, DebuffsConsts.bannedFor, r.data, true)); await commandBus.execute(new SendToastCommand(message, 8000)); await commandBus.execute(new NotifyCardOnScreenCommand(sourceUser.telegramId, this,0 )); eventBus.publish(new CardsSetChangedEvent(sourceUser.telegramId)); }) eventBus.pipe(ofType(NextQuestionEvent)).subscribe(async (r)=> { const players = await queryBus.execute(new FilterGuestsWithPropertyQuery(DebuffsConsts.bannedFor, '$gt', 0)) this.logger.verbose(`enter: ban card handler, banned players count ${players.length}`); players.map(async (player) => { const newBannedFor = parseInt(player.get(StringHelper.getPropertyName(DebuffsConsts.bannedFor))) - 1; await commandBus.execute( new SetGuestPropertyCommand( player.telegramId, DebuffsConsts.bannedFor, newBannedFor.toString() )); }); }) } async handle() { await this.commandBus.execute( new SelectTargetPlayerCommand(this.telegramId, DebuffsConsts.bannedFor, 2,false) ) await this.queryBus.execute(new FilterGuestsWithPropertyQuery(null,null,null)); this.eventBus.subscribe((data) =>{ this.logger.verbose(`Response from cmdBus: ${data}`); }); } } export const gameCards: typeof GameCard[] = [ DoubleTreasureCard, StolePrizeCard, ShitCard, LuckyCard, AvoidPenaltyCard, BanPlayer, VersusCard, ];