Skip to content

Commit

Permalink
fix(actor): actor not powerless on some interactions with elder and a…
Browse files Browse the repository at this point in the history
…ccursed wolf-father (#766)

Closes #744
  • Loading branch information
antoinezanardi committed Dec 20, 2023
1 parent ee85bac commit e6ec0c0
Show file tree
Hide file tree
Showing 4 changed files with 12,485 additions and 11,476 deletions.
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { Injectable } from "@nestjs/common";

import type { GameSource } from "@/modules/game/types/game.type";
import type { PlayerAttribute } from "@/modules/game/schemas/player/player-attribute/player-attribute.schema";
import { GamePhases } from "@/modules/game/enums/game.enum";
import { PlayerAttributeNames } from "@/modules/game/enums/player.enum";
import { createGame } from "@/modules/game/helpers/game.factory";
import { getNearestAliveNeighbor, getPlayerWithIdOrThrow } from "@/modules/game/helpers/game.helper";
import { addPlayerAttributeInGame, updatePlayerInGame } from "@/modules/game/helpers/game.mutator";
import { createGrowledByBearTamerPlayerAttribute } from "@/modules/game/helpers/player/player-attribute/player-attribute.factory";
import { doesPlayerHaveActiveAttributeWithName, getActivePlayerAttributeWithName } from "@/modules/game/helpers/player/player-attribute/player-attribute.helper";
import { createGrowledByBearTamerPlayerAttribute, createPowerlessByAccursedWolfFatherPlayerAttribute } from "@/modules/game/helpers/player/player-attribute/player-attribute.factory";
import { doesPlayerHaveActiveAttributeWithName, doesPlayerHaveActiveAttributeWithNameAndSource, getActivePlayerAttributeWithName } from "@/modules/game/helpers/player/player-attribute/player-attribute.helper";
import { createPlayer } from "@/modules/game/helpers/player/player.factory";
import { isPlayerAliveAndPowerful } from "@/modules/game/helpers/player/player.helper";
import { GamePlayService } from "@/modules/game/providers/services/game-play/game-play.service";
import { PlayerAttributeService } from "@/modules/game/providers/services/player/player-attribute.service";
import type { Game } from "@/modules/game/schemas/game.schema";
import type { Player } from "@/modules/game/schemas/player/player.schema";
import type { GameSource } from "@/modules/game/types/game.type";
import { RoleNames, RoleSides } from "@/modules/role/enums/role.enum";

import { createCantFindPlayerWithIdUnexpectedException } from "@/shared/exception/helpers/unexpected-exception.factory";
Expand Down Expand Up @@ -118,12 +119,30 @@ export class GamePhaseService {
return clonedGame;
}

private isActingPlayerAttributeRelevantOnStartingNight(attribute: PlayerAttribute, game: Game): boolean {
const { isPowerlessOnWerewolvesSide: isActorPowerlessOnWerewolvesSide } = game.options.roles.actor;
const { source, name } = attribute;
const irrelevantAttributeNames = [PlayerAttributeNames.ACTING, PlayerAttributeNames.POWERLESS];
const stickyPowerlessSourceNames: GameSource[] = [RoleNames.ACTOR, RoleNames.ELDER];
const isStickyPowerlessAttributeFromAccursedWolfFather = source === RoleNames.ACCURSED_WOLF_FATHER && isActorPowerlessOnWerewolvesSide;
const isStickyPowerlessAttribute = name === PlayerAttributeNames.POWERLESS &&
(stickyPowerlessSourceNames.includes(source) || isStickyPowerlessAttributeFromAccursedWolfFather);
return !irrelevantAttributeNames.includes(name) || isStickyPowerlessAttribute;
}

private applyStartingNightActingPlayerOutcomes(actingPlayer: Player, game: Game): Game {
const clonedGame = createGame(game);
const stickyPowerlessSources: GameSource[] = [RoleNames.ACCURSED_WOLF_FATHER, RoleNames.ACTOR];
const attributes = actingPlayer.attributes.filter(({ name, source }) =>
name !== PlayerAttributeNames.ACTING && name !== PlayerAttributeNames.POWERLESS ||
name === PlayerAttributeNames.POWERLESS && stickyPowerlessSources.includes(source));
const { isPowerlessOnWerewolvesSide: isActorPowerlessOnWerewolvesSide } = clonedGame.options.roles.actor;
const attributes = actingPlayer.attributes.filter(attribute => this.isActingPlayerAttributeRelevantOnStartingNight(attribute, clonedGame));
const isActorAlreadyPowerlessFromAccursedWolfFather = doesPlayerHaveActiveAttributeWithNameAndSource(
actingPlayer,
PlayerAttributeNames.POWERLESS,
RoleNames.ACCURSED_WOLF_FATHER,
clonedGame,
);
if (isActorPowerlessOnWerewolvesSide && !isActorAlreadyPowerlessFromAccursedWolfFather && actingPlayer.side.current === RoleSides.WEREWOLVES) {
attributes.push(createPowerlessByAccursedWolfFatherPlayerAttribute());
}
const playerDataToUpdate: Partial<Player> = { role: { ...actingPlayer.role, current: RoleNames.ACTOR, isRevealed: false }, attributes };
return updatePlayerInGame(actingPlayer._id, playerDataToUpdate, clonedGame);
}
Expand Down
98 changes: 97 additions & 1 deletion tests/acceptance/features/game/features/role/actor.feature
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,39 @@ Feature: 🎭 Actor role
And the request exception message should be "Bad game play payload"
And the request exception error should be "Chosen card is not for actor"

Scenario: 🎭 Actor can't choose another card if he becomes powerless by elder

Given a created game with additional cards described in file cupid-defender-hunter-additional-cards-for-actor.json and with options described in file no-sheriff-option.json and with the following players
| name | role |
| Antoine | actor |
| Olivia | villager |
| JB | werewolf |
| Thomas | elder |
Then the game's current play should be actor to choose-card

When the actor chooses card with role hunter
Then the player named Antoine should be currently a hunter and originally a actor
And the game's additional card with role hunter for actor should be used
And the game's current play should be werewolves to eat

When the werewolves eat the player named Thomas
Then the player named Thomas should be alive
And the game's current play should be survivors to vote

When the survivors vote with the following votes
| voter | target |
| JB | Thomas |
Then the player named Thomas should be murdered by survivors from vote
And the game's current play should be survivors to bury-dead-bodies

When the survivors bury dead bodies
Then the following players should have the active powerless from elder attribute
| name |
| Antoine |
| Olivia |
And the game's current play should be werewolves to eat


Scenario: 🎭 Actor acts as cupid, defender and hunter

Given a created game with additional cards described in file cupid-defender-hunter-additional-cards-for-actor.json and with options described in file no-sheriff-option.json and with the following players
Expand Down Expand Up @@ -717,7 +750,70 @@ Feature: 🎭 Actor role
When the player or group skips his turn
Then the game's current play should be werewolves to eat

Scenario: 🎭 Actor doesn't become powerless when he is infected by the accursed wolf-father with good game option
Scenario: 🎭 Actor becomes powerless when he is infected by the accursed wolf-father, even if his role is not powerless if infected

Given a created game with additional cards described in file pied-piper-scandalmonger-seer-additional-cards-for-actor.json and with options described in file no-sheriff-option.json, pied-piper-not-powerless-on-werewolves-side-option.json and with the following players
| name | role |
| Antoine | actor |
| Olivia | villager |
| JB | werewolf |
| Thomas | villager |
| Louise | accursed-wolf-father |
Then the game's current play should be actor to choose-card

When the actor chooses card with role pied-piper
Then the player named Antoine should be currently a pied-piper and originally a actor
And the game's additional card with role pied-piper for actor should be used
And the game's current play should be werewolves to eat

When the accursed wolf-father infects the player named Antoine
Then the player named Antoine should be on werewolves current side and originally be on villagers side
And the player named Antoine should not have the active powerless from accursed-wolf-father attribute
And the game's current play should be pied-piper to charm

When the pied piper charms the following players
| name |
| JB |
| Thomas |
Then the player named JB should have the active charmed from pied-piper attribute
And the player named Thomas should have the active charmed from pied-piper attribute
And the game's current play should be charmed to meet-each-other

When the charmed people meet each other
Then the game's current play should be survivors to vote

When the player or group skips his turn
Then the player named Antoine should be currently a actor and originally a actor
And the player named Antoine should have the active powerless from accursed-wolf-father attribute
And the game's current play should be werewolves to eat

Scenario: 🎭 Actor doesn't become powerless when he is infected by the accursed wolf-father with good game option when acting with a role that is powerless if infected

Given a created game with additional cards described in file pied-piper-scandalmonger-seer-additional-cards-for-actor.json and with options described in file no-sheriff-option.json, actor-not-powerless-on-werewolves-side-option.json and with the following players
| name | role |
| Antoine | actor |
| Olivia | villager |
| JB | werewolf |
| Thomas | villager |
| Louise | accursed-wolf-father |
Then the game's current play should be actor to choose-card

When the actor chooses card with role pied-piper
Then the player named Antoine should be currently a pied-piper and originally a actor
And the game's additional card with role pied-piper for actor should be used
And the game's current play should be werewolves to eat

When the accursed wolf-father infects the player named Antoine
Then the player named Antoine should be on werewolves current side and originally be on villagers side
And the player named Antoine should have the active powerless from accursed-wolf-father attribute
And the game's current play should be survivors to vote

When the player or group skips his turn
Then the player named Antoine should be currently a actor and originally a actor
And the player named Antoine should not have the active powerless from accursed-wolf-father attribute
And the game's current play should be actor to choose-card

Scenario: 🎭 Actor doesn't become powerless when he is infected by the accursed wolf-father with good game option when acting with a role that is not powerless if infected

Given a created game with additional cards described in file pied-piper-scandalmonger-seer-additional-cards-for-actor.json and with options described in file no-sheriff-option.json, actor-not-powerless-on-werewolves-side-option.json and with the following players
| name | role |
Expand Down

0 comments on commit e6ec0c0

Please sign in to comment.