Skip to content

Commit

Permalink
feat(game-options): game option to prevent witch to know werewolves t…
Browse files Browse the repository at this point in the history
…argets (#686)

Closes #676
  • Loading branch information
antoinezanardi committed Nov 28, 2023
1 parent 135aa63 commit 62b978f
Show file tree
Hide file tree
Showing 11 changed files with 2,425 additions and 2,267 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const DEFAULT_GAME_OPTIONS: ReadonlyDeep<GameOptions> = {
isPowerlessIfInfected: true,
},
raven: { markPenalty: 2 },
witch: { doesKnowWerewolvesTargets: true },
},
};

Expand Down
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 { 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 { CreateAncientGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-ancient-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 @@ -201,6 +202,15 @@ class CreateRolesGameOptionsDto {
@Type(() => CreateRavenGameOptionsDto)
@ValidateNested()
public raven: CreateRavenGameOptionsDto = new CreateRavenGameOptionsDto();

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

export { CreateRolesGameOptionsDto };
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 { WITCH_GAME_OPTIONS_API_PROPERTIES, WITCH_GAME_OPTIONS_FIELDS_SPECS } from "@/modules/game/schemas/game-options/roles-game-options/witch-game-options/witch-game-options.schema.constant";

class CreateWitchGameOptionsDto {
@ApiProperty({
...WITCH_GAME_OPTIONS_API_PROPERTIES.doesKnowWerewolvesTargets,
required: false,
} as ApiPropertyOptions)
@IsOptional()
@IsBoolean()
public doesKnowWerewolvesTargets: boolean = WITCH_GAME_OPTIONS_FIELDS_SPECS.doesKnowWerewolvesTargets.default;
}

export { CreateWitchGameOptionsDto };
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 { WITCH_GAME_OPTIONS_SCHEMA } from "@/modules/game/schemas/game-options/roles-game-options/witch-game-options/witch-game-options.schema";
import { ANCIENT_GAME_OPTIONS_SCHEMA } from "@/modules/game/schemas/game-options/roles-game-options/ancient-game-options/ancient-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";
import { BIG_BAD_WOLF_GAME_OPTIONS_SCHEMA } from "@/modules/game/schemas/game-options/roles-game-options/big-bad-wolf-game-options/big-bad-wolf-game-options.schema";
Expand Down Expand Up @@ -124,6 +125,11 @@ const ROLES_GAME_OPTIONS_FIELDS_SPECS = {
type: RAVEN_GAME_OPTIONS_SCHEMA,
default: DEFAULT_GAME_OPTIONS.roles.raven,
},
witch: {
required: true,
type: WITCH_GAME_OPTIONS_SCHEMA,
default: DEFAULT_GAME_OPTIONS.roles.witch,
},
} as const satisfies Record<keyof RolesGameOptions, MongoosePropOptions>;

const ROLES_GAME_OPTIONS_API_PROPERTIES: ReadonlyDeep<Record<keyof RolesGameOptions, ApiPropertyOptions>> = {
Expand Down Expand Up @@ -204,6 +210,10 @@ const ROLES_GAME_OPTIONS_API_PROPERTIES: ReadonlyDeep<Record<keyof RolesGameOpti
description: "Game `raven` role's options.",
...convertMongoosePropOptionsToApiPropertyOptions(ROLES_GAME_OPTIONS_FIELDS_SPECS.raven),
},
witch: {
description: "Game `witch` role's options.",
...convertMongoosePropOptionsToApiPropertyOptions(ROLES_GAME_OPTIONS_FIELDS_SPECS.witch),
},
};

export {
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 { 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 { AncientGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/ancient-game-options/ancient-game-options.schema";
import { BearTamerGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/bear-tamer-game-options/bear-tamer-game-options.schema";
Expand Down Expand Up @@ -146,6 +147,11 @@ class RolesGameOptions {
@Type(() => RavenGameOptions)
@Expose()
public raven: RavenGameOptions;

@ApiProperty(ROLES_GAME_OPTIONS_API_PROPERTIES.witch as ApiPropertyOptions)
@Prop(ROLES_GAME_OPTIONS_FIELDS_SPECS.witch)
@Type(() => WitchGameOptions)
public witch: WitchGameOptions;
}

const ROLES_GAME_OPTIONS_SCHEMA = SchemaFactory.createForClass(RolesGameOptions);
Expand Down
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 { WitchGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/witch-game-options/witch-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 WITCH_GAME_OPTIONS_FIELDS_SPECS = {
doesKnowWerewolvesTargets: {
required: true,
default: DEFAULT_GAME_OPTIONS.roles.witch.doesKnowWerewolvesTargets,
},
} as const satisfies Record<keyof WitchGameOptions, MongoosePropOptions>;

const WITCH_GAME_OPTIONS_API_PROPERTIES: ReadonlyDeep<Record<keyof WitchGameOptions, ApiPropertyOptions>> = {
doesKnowWerewolvesTargets: {
description: "If set to `true`, the game master will point out the werewolves' targets to the witch to know which one she can save with her life potion.",
...convertMongoosePropOptionsToApiPropertyOptions(WITCH_GAME_OPTIONS_FIELDS_SPECS.doesKnowWerewolvesTargets),
},
};

export {
WITCH_GAME_OPTIONS_API_PROPERTIES,
WITCH_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 { WITCH_GAME_OPTIONS_API_PROPERTIES, WITCH_GAME_OPTIONS_FIELDS_SPECS } from "@/modules/game/schemas/game-options/roles-game-options/witch-game-options/witch-game-options.schema.constant";

@Schema({
versionKey: false,
id: false,
_id: false,
})
class WitchGameOptions {
@ApiProperty(WITCH_GAME_OPTIONS_API_PROPERTIES.doesKnowWerewolvesTargets as ApiPropertyOptions)
@Prop(WITCH_GAME_OPTIONS_FIELDS_SPECS.doesKnowWerewolvesTargets)
@Expose()
public doesKnowWerewolvesTargets: boolean;
}

const WITCH_GAME_OPTIONS_SCHEMA = SchemaFactory.createForClass(WitchGameOptions);

export {
WitchGameOptions,
WITCH_GAME_OPTIONS_SCHEMA,
};
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,7 @@ describe("Game Controller", () => {
isPowerlessIfInfected: false,
},
raven: { markPenalty: 5 },
witch: { doesKnowWerewolvesTargets: false },
},
};
const payload = createFakeCreateGameWithPlayersDto({}, { options });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { faker } from "@faker-js/faker";
import { plainToInstance } from "class-transformer";

import { CreateWitchGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-witch-game-options.dto";
import { CreateAncientGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-ancient-game-options.dto";
import { CreateBearTamerGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-bear-tamer-game-options.dto";
import { CreateBigBadWolfGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-big-bad-wolf-game-options.dto";
Expand All @@ -25,6 +26,13 @@ import { GamePhases } from "@/modules/game/enums/game.enum";

import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constant";

function createFakeCreateWitchGameOptionsDto(witchGameOptions: Partial<CreateWitchGameOptionsDto> = {}, override: object = {}): CreateWitchGameOptionsDto {
return plainToInstance(CreateWitchGameOptionsDto, {
doesKnowWerewolvesTargets: witchGameOptions.doesKnowWerewolvesTargets ?? faker.datatype.boolean(),
...override,
}, DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);
}

function createFakeCreateRavenGameOptionsDto(ravenGameOptions: Partial<CreateRavenGameOptionsDto> = {}, override: object = {}): CreateRavenGameOptionsDto {
return plainToInstance(CreateRavenGameOptionsDto, {
markPenalty: ravenGameOptions.markPenalty ?? faker.number.int({ min: 1, max: 5 }),
Expand Down Expand Up @@ -199,11 +207,13 @@ function createFakeRolesGameOptionsDto(rolesGameOptions: Partial<CreateRolesGame
thief: createFakeCreateThiefGameOptionsDto(rolesGameOptions.thief),
piedPiper: createFakeCreatePiedPiperGameOptionsDto(rolesGameOptions.piedPiper),
raven: createFakeCreateRavenGameOptionsDto(rolesGameOptions.raven),
witch: createFakeCreateWitchGameOptionsDto(rolesGameOptions.witch),
...override,
}, DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);
}

export {
createFakeCreateWitchGameOptionsDto,
createFakeCreateRavenGameOptionsDto,
createFakeCreatePiedPiperGameOptionsDto,
createFakeCreateThiefGameOptionsDto,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { faker } from "@faker-js/faker";
import { plainToInstance } from "class-transformer";

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 { AncientGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/ancient-game-options/ancient-game-options.schema";
import { BearTamerGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/bear-tamer-game-options/bear-tamer-game-options.schema";
Expand All @@ -25,6 +26,13 @@ import { WildChildGameOptions } from "@/modules/game/schemas/game-options/roles-

import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constant";

function createFakeWitchGameOptions(witchGameOptions: Partial<WitchGameOptions> = {}, override: object = {}): WitchGameOptions {
return plainToInstance(WitchGameOptions, {
doesKnowWerewolvesTargets: witchGameOptions.doesKnowWerewolvesTargets ?? faker.datatype.boolean(),
...override,
}, DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);
}

function createFakeRavenGameOptions(ravenGameOptions: Partial<RavenGameOptions> = {}, override: object = {}): RavenGameOptions {
return plainToInstance(RavenGameOptions, {
markPenalty: ravenGameOptions.markPenalty ?? faker.number.int({ min: 1, max: 5 }),
Expand Down Expand Up @@ -187,11 +195,13 @@ function createFakeRolesGameOptions(rolesGameOptions: Partial<RolesGameOptions>
thief: createFakeThiefGameOptions(rolesGameOptions.thief),
piedPiper: createFakePiedPiperGameOptions(rolesGameOptions.piedPiper),
raven: createFakeRavenGameOptions(rolesGameOptions.raven),
witch: createFakeWitchGameOptions(rolesGameOptions.witch),
...override,
}, DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);
}

export {
createFakeWitchGameOptions,
createFakeRavenGameOptions,
createFakePiedPiperGameOptions,
createFakeThiefGameOptions,
Expand Down

0 comments on commit 62b978f

Please sign in to comment.