Skip to content

Commit

Permalink
feat(game-play): occurrences for game plays (#558)
Browse files Browse the repository at this point in the history
  • Loading branch information
antoinezanardi committed Oct 11, 2023
1 parent 56d254c commit fdf28d0
Show file tree
Hide file tree
Showing 54 changed files with 32,700 additions and 31,632 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { ReadonlyDeep } from "type-fest";

import { GamePhases } from "@/modules/game/enums/game.enum";
import type { GameOptions } from "@/modules/game/schemas/game-options/game-options.schema";

const DEFAULT_GAME_OPTIONS: Readonly<GameOptions> = Object.freeze({
const DEFAULT_GAME_OPTIONS: ReadonlyDeep<GameOptions> = {
composition: { isHidden: false },
votes: { canBeSkipped: true },
roles: {
Expand Down Expand Up @@ -45,6 +47,6 @@ const DEFAULT_GAME_OPTIONS: Readonly<GameOptions> = Object.freeze({
},
raven: { markPenalty: 2 },
},
});
} as const;

export { DEFAULT_GAME_OPTIONS };
80 changes: 37 additions & 43 deletions src/modules/game/constants/game-play/game-play.constant.ts
Original file line number Diff line number Diff line change
@@ -1,70 +1,64 @@
import { GamePlayActions, GamePlayCauses } from "@/modules/game/enums/game-play.enum";
import { createGamePlaySurvivorsElectSheriff, createGamePlaySurvivorsVote, createGamePlayBigBadWolfEats, createGamePlayCharmedMeetEachOther, createGamePlayCupidCharms, createGamePlayDogWolfChoosesSide, createGamePlayFoxSniffs, createGamePlayGuardProtects, createGamePlayHunterShoots, createGamePlayLoversMeetEachOther, createGamePlayPiedPiperCharms, createGamePlayRavenMarks, createGamePlayScapegoatBansVoting, createGamePlaySeerLooks, createGamePlaySheriffDelegates, createGamePlayStutteringJudgeChoosesSign, createGamePlayThiefChoosesCard, createGamePlayThreeBrothersMeetEachOther, createGamePlayTwoSistersMeetEachOther, createGamePlayWerewolvesEat, createGamePlayWhiteWerewolfEats, createGamePlayWildChildChoosesModel, createGamePlayWitchUsesPotions, createGamePlaySheriffSettlesVotes } from "@/modules/game/helpers/game-play/game-play.factory";
import type { GamePlay } from "@/modules/game/schemas/game-play/game-play.schema";
import { GamePlayActions } from "@/modules/game/enums/game-play.enum";
import { PlayerAttributeNames, PlayerGroups } from "@/modules/game/enums/player.enum";
import { RoleNames } from "@/modules/role/enums/role.enum";

const REQUIRED_TARGET_ACTIONS: Readonly<GamePlayActions[]> = Object.freeze([
const GAME_PLAY_SOURCE_NAMES = [
PlayerAttributeNames.SHERIFF,
PlayerGroups.CHARMED,
PlayerGroups.LOVERS,
PlayerGroups.SURVIVORS,
PlayerGroups.WEREWOLVES,
RoleNames.BIG_BAD_WOLF,
RoleNames.CUPID,
RoleNames.DOG_WOLF,
RoleNames.FOX,
RoleNames.GUARD,
RoleNames.HUNTER,
RoleNames.PIED_PIPER,
RoleNames.RAVEN,
RoleNames.SCAPEGOAT,
RoleNames.SEER,
RoleNames.STUTTERING_JUDGE,
RoleNames.THIEF,
RoleNames.THREE_BROTHERS,
RoleNames.TWO_SISTERS,
RoleNames.WHITE_WEREWOLF,
RoleNames.WILD_CHILD,
RoleNames.WITCH,
] as const satisfies Readonly<(PlayerAttributeNames | PlayerGroups | RoleNames)[]>;

const REQUIRED_TARGET_ACTIONS = [
GamePlayActions.LOOK,
GamePlayActions.CHARM,
GamePlayActions.SHOOT,
GamePlayActions.PROTECT,
GamePlayActions.CHOOSE_MODEL,
GamePlayActions.DELEGATE,
GamePlayActions.SETTLE_VOTES,
]);
] as const satisfies Readonly<GamePlayActions[]>;

const OPTIONAL_TARGET_ACTIONS: Readonly<GamePlayActions[]> = Object.freeze([
const OPTIONAL_TARGET_ACTIONS = [
GamePlayActions.EAT,
GamePlayActions.USE_POTIONS,
GamePlayActions.MARK,
GamePlayActions.SNIFF,
GamePlayActions.BAN_VOTING,
]);
] as const satisfies Readonly<GamePlayActions[]>;

const REQUIRED_VOTE_ACTIONS: Readonly<GamePlayActions[]> = Object.freeze([
const REQUIRED_VOTE_ACTIONS = [
GamePlayActions.VOTE,
GamePlayActions.ELECT_SHERIFF,
]);
] as const satisfies Readonly<GamePlayActions[]>;

const STUTTERING_JUDGE_REQUEST_OPPORTUNITY_ACTIONS: Readonly<GamePlayActions[]> = Object.freeze([
const STUTTERING_JUDGE_REQUEST_OPPORTUNITY_ACTIONS = [
GamePlayActions.VOTE,
GamePlayActions.SETTLE_VOTES,
]);

const GAME_PLAYS_PRIORITY_LIST: Readonly<GamePlay[]> = Object.freeze([
createGamePlayHunterShoots(),
createGamePlaySurvivorsElectSheriff({ cause: GamePlayCauses.PREVIOUS_VOTES_WERE_IN_TIES }),
createGamePlaySurvivorsElectSheriff(),
createGamePlaySheriffDelegates(),
createGamePlayScapegoatBansVoting(),
createGamePlaySheriffSettlesVotes(),
createGamePlaySurvivorsVote({ cause: GamePlayCauses.PREVIOUS_VOTES_WERE_IN_TIES }),
createGamePlaySurvivorsVote({ cause: GamePlayCauses.ANGEL_PRESENCE }),
createGamePlaySurvivorsVote({ cause: GamePlayCauses.STUTTERING_JUDGE_REQUEST }),
createGamePlaySurvivorsVote(),
createGamePlayThiefChoosesCard(),
createGamePlayDogWolfChoosesSide(),
createGamePlayCupidCharms(),
createGamePlaySeerLooks(),
createGamePlayFoxSniffs(),
createGamePlayLoversMeetEachOther(),
createGamePlayStutteringJudgeChoosesSign(),
createGamePlayTwoSistersMeetEachOther(),
createGamePlayThreeBrothersMeetEachOther(),
createGamePlayWildChildChoosesModel(),
createGamePlayRavenMarks(),
createGamePlayGuardProtects(),
createGamePlayWerewolvesEat(),
createGamePlayWhiteWerewolfEats(),
createGamePlayBigBadWolfEats(),
createGamePlayWitchUsesPotions(),
createGamePlayPiedPiperCharms(),
createGamePlayCharmedMeetEachOther(),
]);
] as const satisfies Readonly<GamePlayActions[]>;

export {
GAME_PLAY_SOURCE_NAMES,
REQUIRED_TARGET_ACTIONS,
OPTIONAL_TARGET_ACTIONS,
REQUIRED_VOTE_ACTIONS,
STUTTERING_JUDGE_REQUEST_OPPORTUNITY_ACTIONS,
GAME_PLAYS_PRIORITY_LIST,
};
97 changes: 82 additions & 15 deletions src/modules/game/constants/game.constant.ts
Original file line number Diff line number Diff line change
@@ -1,103 +1,170 @@
import { GamePlayActions, GamePlayCauses } from "@/modules/game/enums/game-play.enum";
import type { ReadonlyDeep } from "type-fest";

import { GamePlayActions, GamePlayCauses, GamePlayOccurrences } from "@/modules/game/enums/game-play.enum";
import { PlayerAttributeNames, PlayerGroups } from "@/modules/game/enums/player.enum";
import type { GamePlay } from "@/modules/game/schemas/game-play/game-play.schema";
import type { GameSource } from "@/modules/game/types/game.type";
import { RoleNames } from "@/modules/role/enums/role.enum";

const GAME_SOURCE_VALUES: Readonly<GameSource[]> = Object.freeze([
const GAME_SOURCES = [
...Object.values(PlayerGroups),
...Object.values(RoleNames),
PlayerAttributeNames.SHERIFF,
]);
] as const satisfies Readonly<(PlayerAttributeNames | PlayerGroups | RoleNames)[]>;

const GAME_PLAYS_NIGHT_ORDER: Readonly<(GamePlay & { isFirstNightOnly?: boolean })[]> = Object.freeze([
const GAME_PLAYS_PRIORITY_LIST: ReadonlyDeep<GamePlay[]> = [
{
source: { name: RoleNames.HUNTER },
action: GamePlayActions.SHOOT,
occurrence: GamePlayOccurrences.CONSEQUENTIAL,
},
{
source: { name: PlayerGroups.SURVIVORS },
action: GamePlayActions.ELECT_SHERIFF,
cause: GamePlayCauses.PREVIOUS_VOTES_WERE_IN_TIES,
occurrence: GamePlayOccurrences.CONSEQUENTIAL,
},
{
source: { name: PlayerGroups.SURVIVORS },
action: GamePlayActions.ELECT_SHERIFF,
occurrence: GamePlayOccurrences.ANYTIME,
},
{
source: { name: PlayerAttributeNames.SHERIFF },
action: GamePlayActions.DELEGATE,
occurrence: GamePlayOccurrences.CONSEQUENTIAL,
},
{
source: { name: RoleNames.SCAPEGOAT },
action: GamePlayActions.BAN_VOTING,
occurrence: GamePlayOccurrences.CONSEQUENTIAL,
},
{
source: { name: PlayerAttributeNames.SHERIFF },
action: GamePlayActions.SETTLE_VOTES,
occurrence: GamePlayOccurrences.CONSEQUENTIAL,
},
{
source: { name: PlayerGroups.SURVIVORS },
action: GamePlayActions.VOTE,
cause: GamePlayCauses.PREVIOUS_VOTES_WERE_IN_TIES,
occurrence: GamePlayOccurrences.CONSEQUENTIAL,
},
{
source: { name: PlayerGroups.SURVIVORS },
action: GamePlayActions.VOTE,
cause: GamePlayCauses.ANGEL_PRESENCE,
isFirstNightOnly: true,
occurrence: GamePlayOccurrences.FIRST_NIGHT_ONLY,
},
{
source: { name: PlayerGroups.SURVIVORS },
action: GamePlayActions.VOTE,
cause: GamePlayCauses.STUTTERING_JUDGE_REQUEST,
occurrence: GamePlayOccurrences.CONSEQUENTIAL,
},
{
source: { name: PlayerGroups.SURVIVORS },
action: GamePlayActions.VOTE,
occurrence: GamePlayOccurrences.ON_DAYS,
},
{
source: { name: RoleNames.THIEF },
action: GamePlayActions.CHOOSE_CARD,
isFirstNightOnly: true,
occurrence: GamePlayOccurrences.FIRST_NIGHT_ONLY,
},
{
source: { name: RoleNames.DOG_WOLF },
action: GamePlayActions.CHOOSE_SIDE,
isFirstNightOnly: true,
occurrence: GamePlayOccurrences.FIRST_NIGHT_ONLY,
},
{
source: { name: RoleNames.CUPID },
action: GamePlayActions.CHARM,
isFirstNightOnly: true,
occurrence: GamePlayOccurrences.FIRST_NIGHT_ONLY,
},
{
source: { name: RoleNames.SEER },
action: GamePlayActions.LOOK,
occurrence: GamePlayOccurrences.ON_NIGHTS,
},
{
source: { name: RoleNames.FOX },
action: GamePlayActions.SNIFF,
occurrence: GamePlayOccurrences.ON_NIGHTS,
},
{
source: { name: PlayerGroups.LOVERS },
action: GamePlayActions.MEET_EACH_OTHER,
isFirstNightOnly: true,
occurrence: GamePlayOccurrences.FIRST_NIGHT_ONLY,
},
{
source: { name: RoleNames.STUTTERING_JUDGE },
action: GamePlayActions.CHOOSE_SIGN,
isFirstNightOnly: true,
occurrence: GamePlayOccurrences.FIRST_NIGHT_ONLY,
},
{
source: { name: RoleNames.TWO_SISTERS },
action: GamePlayActions.MEET_EACH_OTHER,
occurrence: GamePlayOccurrences.ON_NIGHTS,
},
{
source: { name: RoleNames.THREE_BROTHERS },
action: GamePlayActions.MEET_EACH_OTHER,
occurrence: GamePlayOccurrences.ON_NIGHTS,
},
{
source: { name: RoleNames.WILD_CHILD },
action: GamePlayActions.CHOOSE_MODEL,
isFirstNightOnly: true,
occurrence: GamePlayOccurrences.FIRST_NIGHT_ONLY,
},
{
source: { name: RoleNames.RAVEN },
action: GamePlayActions.MARK,
occurrence: GamePlayOccurrences.ON_NIGHTS,
},
{
source: { name: RoleNames.GUARD },
action: GamePlayActions.PROTECT,
occurrence: GamePlayOccurrences.ON_NIGHTS,
},
{
source: { name: PlayerGroups.WEREWOLVES },
action: GamePlayActions.EAT,
occurrence: GamePlayOccurrences.ON_NIGHTS,
},
{
source: { name: RoleNames.WHITE_WEREWOLF },
action: GamePlayActions.EAT,
occurrence: GamePlayOccurrences.ON_NIGHTS,
},
{
source: { name: RoleNames.BIG_BAD_WOLF },
action: GamePlayActions.EAT,
occurrence: GamePlayOccurrences.ON_NIGHTS,
},
{
source: { name: RoleNames.WITCH },
action: GamePlayActions.USE_POTIONS,
occurrence: GamePlayOccurrences.ON_NIGHTS,
},
{
source: { name: RoleNames.PIED_PIPER },
action: GamePlayActions.CHARM,
occurrence: GamePlayOccurrences.ON_NIGHTS,
},
{
source: { name: PlayerGroups.CHARMED },
action: GamePlayActions.MEET_EACH_OTHER,
occurrence: GamePlayOccurrences.ON_NIGHTS,
},
]);
] as const;

const ON_NIGHTS_GAME_PLAYS_PRIORITY_LIST: ReadonlyDeep<GamePlay[]> = GAME_PLAYS_PRIORITY_LIST.filter(({ occurrence }) => occurrence === GamePlayOccurrences.ON_NIGHTS);

const ON_FIRST_AND_LATER_NIGHTS_GAME_PLAYS_PRIORITY_LIST: ReadonlyDeep<GamePlay[]> = GAME_PLAYS_PRIORITY_LIST.filter(({ occurrence }) => [GamePlayOccurrences.FIRST_NIGHT_ONLY, GamePlayOccurrences.ON_NIGHTS].includes(occurrence));

export {
GAME_SOURCE_VALUES,
GAME_PLAYS_NIGHT_ORDER,
GAME_SOURCES,
GAME_PLAYS_PRIORITY_LIST,
ON_NIGHTS_GAME_PLAYS_PRIORITY_LIST,
ON_FIRST_AND_LATER_NIGHTS_GAME_PLAYS_PRIORITY_LIST,
};
9 changes: 9 additions & 0 deletions src/modules/game/enums/game-play.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ enum GamePlayCauses {
ANGEL_PRESENCE = "angel-presence",
}

enum GamePlayOccurrences {
FIRST_NIGHT_ONLY = "first-night-only",
ON_NIGHTS = "on-nights",
ON_DAYS = "on-days",
ANYTIME = "anytime",
CONSEQUENTIAL = "consequential",
}

enum WitchPotions {
LIFE = "life",
DEATH = "death",
Expand All @@ -33,5 +41,6 @@ enum WitchPotions {
export {
GamePlayActions,
GamePlayCauses,
GamePlayOccurrences,
WitchPotions,
};

0 comments on commit fdf28d0

Please sign in to comment.