Skip to content

Commit

Permalink
feat(game-options): lovers reveal each other role game option (#710)
Browse files Browse the repository at this point in the history
Closes #702
  • Loading branch information
antoinezanardi committed Dec 3, 2023
1 parent 1bd783c commit 7b284d9
Show file tree
Hide file tree
Showing 26 changed files with 8,706 additions and 8,572 deletions.
12 changes: 10 additions & 2 deletions config/eslint/rules/overrides/factory-files.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
const { OFF } = require("../../constants");
const { OFF, ERROR } = require("../../constants");

const factoryFilesOverride = Object.freeze({
files: ["*.factory.ts"],
rules: { "@typescript-eslint/no-magic-numbers": OFF },
rules: {
"@typescript-eslint/no-magic-numbers": OFF,
"import/max-dependencies": [
ERROR, {
max: 30,
ignoreTypeImports: true,
},
],
},
});

module.exports = { factoryFilesOverride };
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const DEFAULT_GAME_OPTIONS: ReadonlyDeep<GameOptions> = {
isTalkative: true,
canSeeRoles: true,
},
cupid: { lovers: { doRevealRoleToEachOther: false } },
littleGirl: { isProtectedByDefender: false },
defender: { canProtectTwice: false },
elder: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { ApiPropertyOptions } from "@nestjs/swagger";
import { ApiProperty } from "@nestjs/swagger";
import { Type } from "class-transformer";
import { IsOptional, ValidateNested } from "class-validator";

import { CreateCupidLoversGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-cupid-game-options/create-cupid-lovers-game-options.dto";
import { CUPID_GAME_OPTIONS_API_PROPERTIES } from "@/modules/game/schemas/game-options/roles-game-options/cupid-game-options/cupid-game-options.schema.constant";

class CreateCupidGameOptionsDto {
@ApiProperty({
...CUPID_GAME_OPTIONS_API_PROPERTIES.lovers,
required: false,
} as ApiPropertyOptions)
@IsOptional()
@Type(() => CreateCupidLoversGameOptionsDto)
@ValidateNested()
public lovers: CreateCupidLoversGameOptionsDto = new CreateCupidLoversGameOptionsDto();
}

export { CreateCupidGameOptionsDto };
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { ApiPropertyOptions } from "@nestjs/swagger";
import { ApiProperty } from "@nestjs/swagger";
import { IsBoolean, IsOptional } from "class-validator";

import { CUPID_LOVERS_GAME_OPTIONS_API_PROPERTIES, CUPID_LOVERS_GAME_OPTIONS_FIELDS_SPECS } from "@/modules/game/schemas/game-options/roles-game-options/cupid-game-options/cupid-lovers-game-options/cupid-game-options.schema.constant";

class CreateCupidLoversGameOptionsDto {
@ApiProperty({
...CUPID_LOVERS_GAME_OPTIONS_API_PROPERTIES.doRevealRoleToEachOther,
required: false,
} as ApiPropertyOptions)
@IsOptional()
@IsBoolean()
public doRevealRoleToEachOther: boolean = CUPID_LOVERS_GAME_OPTIONS_FIELDS_SPECS.doRevealRoleToEachOther.default;
}

export { CreateCupidLoversGameOptionsDto };
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ApiProperty } from "@nestjs/swagger";
import { Type } from "class-transformer";
import { IsBoolean, IsOptional, ValidateNested } from "class-validator";

import { CreateCupidGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-cupid-game-options/create-cupid-game-options.dto";
import { CreateWitchGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-witch-game-options.dto";
import { ROLES_GAME_OPTIONS_API_PROPERTIES, ROLES_GAME_OPTIONS_FIELDS_SPECS } from "@/modules/game/schemas/game-options/roles-game-options/roles-game-options.schema.constant";
import { CreateElderGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-elder-game-options.dto";
Expand Down Expand Up @@ -77,6 +78,15 @@ class CreateRolesGameOptionsDto {
@ValidateNested()
public seer: CreateSeerGameOptionsDto = new CreateSeerGameOptionsDto();

@ApiProperty({
...ROLES_GAME_OPTIONS_API_PROPERTIES.cupid,
required: false,
} as ApiPropertyOptions)
@IsOptional()
@Type(() => CreateCupidGameOptionsDto)
@ValidateNested()
public cupid: CreateCupidGameOptionsDto = new CreateCupidGameOptionsDto();

@ApiProperty({
...ROLES_GAME_OPTIONS_API_PROPERTIES.littleGirl,
required: false,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { ApiPropertyOptions } from "@nestjs/swagger";
import type { ReadonlyDeep } from "type-fest";

import type { CupidGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/cupid-game-options/cupid-game-options.schema";
import { CUPID_LOVERS_GAME_OPTIONS_SCHEMA } from "@/modules/game/schemas/game-options/roles-game-options/cupid-game-options/cupid-lovers-game-options/cupid-game-options.schema";
import { DEFAULT_GAME_OPTIONS } from "@/modules/game/constants/game-options/game-options.constant";

import { convertMongoosePropOptionsToApiPropertyOptions } from "@/shared/api/helpers/api.helper";
import type { MongoosePropOptions } from "@/shared/mongoose/types/mongoose.types";

const CUPID_GAME_OPTIONS_FIELDS_SPECS = {
lovers: {
required: true,
type: CUPID_LOVERS_GAME_OPTIONS_SCHEMA,
default: DEFAULT_GAME_OPTIONS.roles.cupid.lovers,
},
} as const satisfies Record<keyof CupidGameOptions, MongoosePropOptions>;

const CUPID_GAME_OPTIONS_API_PROPERTIES: ReadonlyDeep<Record<keyof CupidGameOptions, ApiPropertyOptions>> = {
lovers: {
description: "Game lovers from `cupid` role options.",
...convertMongoosePropOptionsToApiPropertyOptions(CUPID_GAME_OPTIONS_FIELDS_SPECS.lovers),
},
};

export {
CUPID_GAME_OPTIONS_API_PROPERTIES,
CUPID_GAME_OPTIONS_FIELDS_SPECS,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";
import type { ApiPropertyOptions } from "@nestjs/swagger";
import { ApiProperty } from "@nestjs/swagger";
import { Expose, Type } from "class-transformer";

import { CUPID_GAME_OPTIONS_API_PROPERTIES, CUPID_GAME_OPTIONS_FIELDS_SPECS } from "@/modules/game/schemas/game-options/roles-game-options/cupid-game-options/cupid-game-options.schema.constant";
import { CupidLoversGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/cupid-game-options/cupid-lovers-game-options/cupid-game-options.schema";

@Schema({
versionKey: false,
id: false,
_id: false,
})
class CupidGameOptions {
@ApiProperty(CUPID_GAME_OPTIONS_API_PROPERTIES.lovers as ApiPropertyOptions)
@Prop(CUPID_GAME_OPTIONS_FIELDS_SPECS.lovers)
@Type(() => CupidLoversGameOptions)
@Expose()
public lovers: CupidLoversGameOptions;
}

const CUPID_GAME_OPTIONS_SCHEMA = SchemaFactory.createForClass(CupidGameOptions);

export {
CupidGameOptions,
CUPID_GAME_OPTIONS_SCHEMA,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { ApiPropertyOptions } from "@nestjs/swagger";
import type { ReadonlyDeep } from "type-fest";

import type { CupidLoversGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/cupid-game-options/cupid-lovers-game-options/cupid-game-options.schema";
import { DEFAULT_GAME_OPTIONS } from "@/modules/game/constants/game-options/game-options.constant";

import { convertMongoosePropOptionsToApiPropertyOptions } from "@/shared/api/helpers/api.helper";
import type { MongoosePropOptions } from "@/shared/mongoose/types/mongoose.types";

const CUPID_LOVERS_GAME_OPTIONS_FIELDS_SPECS = {
doRevealRoleToEachOther: {
required: true,
default: DEFAULT_GAME_OPTIONS.roles.cupid.lovers.doRevealRoleToEachOther,
},
} as const satisfies Record<keyof CupidLoversGameOptions, MongoosePropOptions>;

const CUPID_LOVERS_GAME_OPTIONS_API_PROPERTIES: ReadonlyDeep<Record<keyof CupidLoversGameOptions, ApiPropertyOptions>> = {
doRevealRoleToEachOther: {
description: "If set to `true`, the lovers will know each other's role when they are meeting at the beginning of the game",
...convertMongoosePropOptionsToApiPropertyOptions(CUPID_LOVERS_GAME_OPTIONS_FIELDS_SPECS.doRevealRoleToEachOther),
},
};

export {
CUPID_LOVERS_GAME_OPTIONS_API_PROPERTIES,
CUPID_LOVERS_GAME_OPTIONS_FIELDS_SPECS,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";
import type { ApiPropertyOptions } from "@nestjs/swagger";
import { ApiProperty } from "@nestjs/swagger";
import { Expose } from "class-transformer";

import { CUPID_LOVERS_GAME_OPTIONS_API_PROPERTIES, CUPID_LOVERS_GAME_OPTIONS_FIELDS_SPECS } from "@/modules/game/schemas/game-options/roles-game-options/cupid-game-options/cupid-lovers-game-options/cupid-game-options.schema.constant";

@Schema({
versionKey: false,
id: false,
_id: false,
})
class CupidLoversGameOptions {
@ApiProperty(CUPID_LOVERS_GAME_OPTIONS_API_PROPERTIES.doRevealRoleToEachOther as ApiPropertyOptions)
@Prop(CUPID_LOVERS_GAME_OPTIONS_FIELDS_SPECS.doRevealRoleToEachOther)
@Expose()
public doRevealRoleToEachOther: boolean;
}

const CUPID_LOVERS_GAME_OPTIONS_SCHEMA = SchemaFactory.createForClass(CupidLoversGameOptions);

export {
CupidLoversGameOptions,
CUPID_LOVERS_GAME_OPTIONS_SCHEMA,
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ApiPropertyOptions } from "@nestjs/swagger";
import type { ReadonlyDeep } from "type-fest";

import { CUPID_GAME_OPTIONS_SCHEMA } from "@/modules/game/schemas/game-options/roles-game-options/cupid-game-options/cupid-game-options.schema";
import { WITCH_GAME_OPTIONS_SCHEMA } from "@/modules/game/schemas/game-options/roles-game-options/witch-game-options/witch-game-options.schema";
import { ELDER_GAME_OPTIONS_SCHEMA } from "@/modules/game/schemas/game-options/roles-game-options/elder-game-options/elder-game-options.schema";
import { BEAR_TAMER_GAME_OPTIONS_SCHEMA } from "@/modules/game/schemas/game-options/roles-game-options/bear-tamer-game-options/bear-tamer-game-options.schema";
Expand Down Expand Up @@ -55,6 +56,11 @@ const ROLES_GAME_OPTIONS_FIELDS_SPECS = {
type: SEER_GAME_OPTIONS_SCHEMA,
default: DEFAULT_GAME_OPTIONS.roles.seer,
},
cupid: {
required: true,
type: CUPID_GAME_OPTIONS_SCHEMA,
default: DEFAULT_GAME_OPTIONS.roles.cupid,
},
littleGirl: {
required: true,
type: LITTLE_GIRL_GAME_OPTIONS_SCHEMA,
Expand Down Expand Up @@ -157,6 +163,10 @@ const ROLES_GAME_OPTIONS_API_PROPERTIES: ReadonlyDeep<Record<keyof RolesGameOpti
description: "Game `seer` role's options.",
...convertMongoosePropOptionsToApiPropertyOptions(ROLES_GAME_OPTIONS_FIELDS_SPECS.seer),
},
cupid: {
description: "Game `cupid` role's options.",
...convertMongoosePropOptionsToApiPropertyOptions(ROLES_GAME_OPTIONS_FIELDS_SPECS.cupid),
},
littleGirl: {
description: "Game `little girl` role's options.",
...convertMongoosePropOptionsToApiPropertyOptions(ROLES_GAME_OPTIONS_FIELDS_SPECS.littleGirl),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { ApiPropertyOptions } from "@nestjs/swagger";
import { ApiProperty } from "@nestjs/swagger";
import { Expose, Type } from "class-transformer";

import { CupidGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/cupid-game-options/cupid-game-options.schema";
import { WitchGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/witch-game-options/witch-game-options.schema";
import { ROLES_GAME_OPTIONS_API_PROPERTIES, ROLES_GAME_OPTIONS_FIELDS_SPECS } from "@/modules/game/schemas/game-options/roles-game-options/roles-game-options.schema.constant";
import { ElderGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/elder-game-options/elder-game-options.schema";
Expand Down Expand Up @@ -64,6 +65,12 @@ class RolesGameOptions {
@Expose()
public seer: SeerGameOptions;

@ApiProperty(ROLES_GAME_OPTIONS_API_PROPERTIES.cupid as ApiPropertyOptions)
@Prop(ROLES_GAME_OPTIONS_FIELDS_SPECS.cupid)
@Type(() => CupidGameOptions)
@Expose()
public cupid: CupidGameOptions;

@ApiProperty(ROLES_GAME_OPTIONS_API_PROPERTIES.littleGirl as ApiPropertyOptions)
@Prop(ROLES_GAME_OPTIONS_FIELDS_SPECS.littleGirl)
@Type(() => LittleGirlGameOptions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { createFakeGameAdditionalCard } from "@tests/factories/game/schemas/game
import { createFakeGameHistoryRecord, createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlaySource } from "@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory";
import { createFakeCompositionGameOptions } from "@tests/factories/game/schemas/game-options/composition-game-options.schema.factory";
import { createFakeGameOptions } from "@tests/factories/game/schemas/game-options/game-options.schema.factory";
import { createFakeRolesGameOptions } from "@tests/factories/game/schemas/game-options/game-roles-options.schema.factory";
import { createFakeRolesGameOptions } from "@tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory";
import { createFakeVotesGameOptions } from "@tests/factories/game/schemas/game-options/votes-game-options.schema.factory";
import { createFakeGamePlayEligibleTargetsBoundaries } from "@tests/factories/game/schemas/game-play/game-play-eligibile-targets/game-play-eligible-targets-boundaries/game-play-eligible-targets-boundaries.schema.factory";
import { createFakeGamePlayEligibleTargets } from "@tests/factories/game/schemas/game-play/game-play-eligibile-targets/game-play-eligible-targets.schema.factory";
Expand Down Expand Up @@ -869,6 +869,7 @@ describe("Game Controller", () => {
isTalkative: false,
canSeeRoles: false,
},
cupid: { lovers: { doRevealRoleToEachOther: true } },
littleGirl: { isProtectedByDefender: true },
defender: { canProtectTwice: true },
elder: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { faker } from "@faker-js/faker";
import { plainToInstance } from "class-transformer";

import { CreateCupidGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-cupid-game-options/create-cupid-game-options.dto";
import { CreateCupidLoversGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-cupid-game-options/create-cupid-lovers-game-options.dto";
import { CreateWitchGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-witch-game-options.dto";
import { CreateElderGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-elder-game-options.dto";
import { CreateBearTamerGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-bear-tamer-game-options.dto";
Expand Down Expand Up @@ -152,6 +154,20 @@ function createFakeCreateSeerGameOptionsDto(seerGameOptions: Partial<CreateSeerG
}, DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);
}

function createFakeCreateCupidLoversGameOptionsDto(cupidLoversGameOptions: Partial<CreateCupidLoversGameOptionsDto> = {}, override: object = {}): CreateCupidLoversGameOptionsDto {
return plainToInstance(CreateCupidLoversGameOptionsDto, {
doRevealRoleToEachOther: cupidLoversGameOptions.doRevealRoleToEachOther ?? faker.datatype.boolean(),
...override,
}, DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);
}

function createFakeCreateCupidGameOptionsDto(cupidGameOptions: Partial<CreateCupidGameOptionsDto> = {}, override: object = {}): CreateCupidGameOptionsDto {
return plainToInstance(CreateCupidGameOptionsDto, {
lovers: createFakeCreateCupidLoversGameOptionsDto(cupidGameOptions.lovers),
...override,
}, DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);
}

function createFakeCreateWhiteWerewolfGameOptionsDto(
whiteWerewolfOptions: Partial<CreateWhiteWerewolfGameOptionsDto> = {},
override: object = {},
Expand Down Expand Up @@ -197,6 +213,7 @@ function createFakeRolesGameOptionsDto(rolesGameOptions: Partial<CreateRolesGame
bigBadWolf: createFakeCreateBigBadWolfGameOptionsDto(rolesGameOptions.bigBadWolf),
whiteWerewolf: createFakeCreateWhiteWerewolfGameOptionsDto(rolesGameOptions.whiteWerewolf),
seer: createFakeCreateSeerGameOptionsDto(rolesGameOptions.seer),
cupid: createFakeCreateCupidGameOptionsDto(rolesGameOptions.cupid),
littleGirl: createFakeCreateLittleGirlGameOptionsDto(rolesGameOptions.littleGirl),
defender: createFakeCreateDefenderGameOptionsDto(rolesGameOptions.defender),
elder: createFakeCreateElderGameOptionsDto(rolesGameOptions.elder),
Expand Down Expand Up @@ -233,6 +250,8 @@ export {
createFakeCreateDefenderGameOptionsDto,
createFakeCreateLittleGirlGameOptionsDto,
createFakeCreateSeerGameOptionsDto,
createFakeCreateCupidLoversGameOptionsDto,
createFakeCreateCupidGameOptionsDto,
createFakeCreateWhiteWerewolfGameOptionsDto,
createFakeCreateBigBadWolfGameOptionsDto,
createFakeCreateSheriffElectionGameOptionsDto,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { GameOptions } from "@/modules/game/schemas/game-options/game-options.sc
import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constant";

import { createFakeCompositionGameOptions } from "@tests/factories/game/schemas/game-options/composition-game-options.schema.factory";
import { createFakeRolesGameOptions } from "@tests/factories/game/schemas/game-options/game-roles-options.schema.factory";
import { createFakeRolesGameOptions } from "@tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory";
import { createFakeVotesGameOptions } from "@tests/factories/game/schemas/game-options/votes-game-options.schema.factory";

function createFakeGameOptions(gameOptions: Partial<GameOptions> = {}, override: object = {}): GameOptions {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { faker } from "@faker-js/faker";
import { plainToInstance } from "class-transformer";

import { CupidGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/cupid-game-options/cupid-game-options.schema";
import { CupidLoversGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/cupid-game-options/cupid-lovers-game-options/cupid-game-options.schema";
import { WitchGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/witch-game-options/witch-game-options.schema";
import { GamePhases } from "@/modules/game/enums/game.enum";
import { ElderGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/elder-game-options/elder-game-options.schema";
Expand Down Expand Up @@ -143,6 +145,20 @@ function createFakeSeerGameOptions(seerGameOptions: Partial<SeerGameOptions> = {
}, DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);
}

function createFakeCupidLoversGameOptions(cupidLoversGameOptions: Partial<CupidLoversGameOptions> = {}, override: object = {}): CupidLoversGameOptions {
return plainToInstance(CupidLoversGameOptions, {
doRevealRoleToEachOther: cupidLoversGameOptions.doRevealRoleToEachOther ?? faker.datatype.boolean(),
...override,
}, DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);
}

function createFakeCupidGameOptions(cupidGameOptions: Partial<CupidGameOptions> = {}, override: object = {}): CupidGameOptions {
return plainToInstance(CupidGameOptions, {
lovers: createFakeCupidLoversGameOptions(cupidGameOptions.lovers),
...override,
}, DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);
}

function createFakeWhiteWerewolfGameOptions(whiteWerewolfOptions: Partial<WhiteWerewolfGameOptions> = {}, override: object = {}): WhiteWerewolfGameOptions {
return plainToInstance(WhiteWerewolfGameOptions, {
wakingUpInterval: whiteWerewolfOptions.wakingUpInterval ?? faker.number.int({ min: 1, max: 5 }),
Expand Down Expand Up @@ -182,6 +198,7 @@ function createFakeRolesGameOptions(rolesGameOptions: Partial<RolesGameOptions>
bigBadWolf: createFakeBigBadWolfGameOptions(rolesGameOptions.bigBadWolf),
whiteWerewolf: createFakeWhiteWerewolfGameOptions(rolesGameOptions.whiteWerewolf),
seer: createFakeSeerGameOptions(rolesGameOptions.seer),
cupid: createFakeCupidGameOptions(rolesGameOptions.cupid),
littleGirl: createFakeLittleGirlGameOptions(rolesGameOptions.littleGirl),
defender: createFakeDefenderGameOptions(rolesGameOptions.defender),
elder: createFakeElderGameOptions(rolesGameOptions.elder),
Expand Down Expand Up @@ -218,6 +235,8 @@ export {
createFakeDefenderGameOptions,
createFakeLittleGirlGameOptions,
createFakeSeerGameOptions,
createFakeCupidGameOptions,
createFakeCupidLoversGameOptions,
createFakeWhiteWerewolfGameOptions,
createFakeBigBadWolfGameOptions,
createFakeSheriffElectionGameOptions,
Expand Down

0 comments on commit 7b284d9

Please sign in to comment.