Skip to content

Commit

Permalink
feat(Game): Implement the White Werewolf role. Closes #126
Browse files Browse the repository at this point in the history
  • Loading branch information
antoinezanardi committed Feb 27, 2021
1 parent 083de4b commit e4c4bd5
Show file tree
Hide file tree
Showing 19 changed files with 149 additions and 39 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* [#123](https://github.com/antoinezanardi/werewolves-assistant-web/issues/123) - Options for game repartition.
* [#124](https://github.com/antoinezanardi/werewolves-assistant-web/issues/124) - Add guard protection on little girl option.
* [#125](https://github.com/antoinezanardi/werewolves-assistant-web/issues/125) - Add idiot dies on ancient death option.
* [#126](https://github.com/antoinezanardi/werewolves-assistant-web/issues/126) - Implement the White Werewolf Role.

### 🌟 Enhancements

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,12 @@ The MongoDB database is protected under username and password authentication.

## <a name="roles-available">🃏 Roles available</a>

On this current version [![GitHub release](https://img.shields.io/github/release/antoinezanardi/werewolves-assistant-web.svg)](https://GitHub.com/antoinezanardi/werewolves-assistant-web/releases/), **20 different roles** are available to play:
On this current version [![GitHub release](https://img.shields.io/github/release/antoinezanardi/werewolves-assistant-web.svg)](https://GitHub.com/antoinezanardi/werewolves-assistant-web/releases/), **21 different roles** are available to play:

- **<img src="https://werewolves-assistant-api.antoinezanardi.fr/img/roles/werewolf.png" width="25"/> The Werewolf**
- **<img src="https://werewolves-assistant-api.antoinezanardi.fr/img/roles/big-bad-wolf.png" width="25"/> The Big-Bad-Wolf**
- **<img src="https://werewolves-assistant-api.antoinezanardi.fr/img/roles/vile-father-of-wolves.png" width="25"/> The Vile Father Of Wolves**
- **<img src="https://werewolves-assistant-api.antoinezanardi.fr/img/roles/white-werewolf.png" width="25"/> The White Werewolf**
- **<img src="https://werewolves-assistant-api.antoinezanardi.fr/img/roles/villager.png" width="25"/> The Villager**
- **<img src="https://werewolves-assistant-api.antoinezanardi.fr/img/roles/villager.png" width="25"/> The Villager-Villager**
- **<img src="https://werewolves-assistant-api.antoinezanardi.fr/img/roles/seer.png" width="25"/> The Seer**
Expand Down
2 changes: 1 addition & 1 deletion src/classes/Game.js
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ class Game {
return false;
}
const { play } = this.history[0];
return play.source.name === "all" && play.action === "vote" && play.targets.length > 1 &&
return play.source.name === "all" && play.action === "vote" && play.votesResult === "need-settlement" &&
this.firstWaiting.for === "all" && this.firstWaiting.to === "vote";
}

Expand Down
10 changes: 6 additions & 4 deletions src/classes/GameHistory.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ class GameHistory {
from: new Player(vote.from),
for: new Player(vote.for),
}))),
votesResult: getProp(gameHistory, "play.votesResult"),
doesJudgeRequestAnotherVote: getProp(gameHistory, "play.doesJudgeRequestAnotherVote"),
chosenCard: getProp(gameHistory, "play.chosenCard"),
side: getProp(gameHistory, "play.side"),
};
this.deadPlayers = getProp(gameHistory, "deadPlayers", [], players => players.map(player => new Player(player)));
Expand All @@ -39,17 +41,17 @@ class GameHistory {

get didWitchUsedLifePotion() {
const { play } = this;
return play.source.name === "witch" && play.action === "use-potion" && !!play.targets.find(({ potion }) => potion.life);
return play.source.name === "witch" && play.action === "use-potion" && !!play.targets.find(({ hasDrankLifePotion }) => hasDrankLifePotion);
}

get didWitchUsedDeathPotion() {
const { play } = this;
return play.source.name === "witch" && play.action === "use-potion" && !!play.targets.find(({ potion }) => potion.death);
return play.source.name === "witch" && play.action === "use-potion" && !!play.targets.find(({ hasDrankDeathPotion }) => hasDrankDeathPotion);
}

get wasVotePlayWithoutDeath() {
const { play, deadPlayers } = this;
return play.source.name === "all" && play.action === "vote" && !deadPlayers.length;
const { play } = this;
return play.source.name === "all" && play.action === "vote" && play.votesResult === "no-death";
}

get hasStutteringJudgeRequestedVote() {
Expand Down
4 changes: 4 additions & 0 deletions src/classes/Player.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ class Player {
get isAliveAndPowerful() {
return this.isAlive && !this.hasAttribute("powerless");
}

get canVote() {
return !this.hasAttribute("cant-vote");
}
}

export default Player;
3 changes: 1 addition & 2 deletions src/components/Game/GameContent/GameContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,7 @@ export default {
} else if (lastGameHistoryEntry.play.action === "eat" && lastGameHistoryEntrySourceName === "werewolves" &&
!!vileFatherOfWolvesPlayer && vileFatherOfWolvesPlayer.isAlive) {
this.events.push(new GameEvent({ type: `vile-father-of-wolves-infects`, targets: lastGameHistoryEntry.play.targets }));
} else if (this.game.history.length > 1 && lastGameHistoryEntry.wasVotePlayWithoutDeath &&
this.game.history[1].wasVotePlayWithoutDeath) {
} else if (this.game.history.length && lastGameHistoryEntry.wasVotePlayWithoutDeath) {
this.events.push(new GameEvent({ type: `no-death-after-votes`, targets: this.game.history[1].play.targets }));
} else if (lastGameHistoryEntry.play.action === "choose-card") {
this.events.push(new GameEvent({ type: `thief-chooses-card`, targets: [{ player: this.game.originalThiefPlayer }] }));
Expand Down
20 changes: 16 additions & 4 deletions src/components/Game/GameContent/GamePlayField/GamePlayField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export default {
pastEvents: {
lastGuardTarget: undefined,
hasWitchUsedLifePotion: undefined,
hasWitchUsedLDeathPotion: undefined,
hasWitchUsedDeathPotion: undefined,
hasStutteringJudgeChosenSign: undefined,
hasStutteringJudgeRequestedVote: undefined,
hasVileFatherOfWolvesInfected: undefined,
Expand Down Expand Up @@ -88,7 +88,7 @@ export default {
this.loadings.pastEvents = true;
const eatQueryStrings = { "play-source": "werewolves", "play-action": "eat" };
const { data } = await this.$werewolvesAssistantAPI.getGameHistory(this.game._id, eatQueryStrings);
const eatPlays = data.map(eatPlay => new GameHistory(eatPlay));
const eatPlays = data.map(gameHistoryEntry => new GameHistory(gameHistoryEntry));
this.pastEvents.hasVileFatherOfWolvesInfected = !!eatPlays.find(play => play.didVileFatherOfWolvesInfectTarget);
},
async fillStutteringJudgePastEvents() {
Expand All @@ -101,11 +101,22 @@ export default {
const votePlays = data.map(gameHistoryEntry => new GameHistory(gameHistoryEntry));
this.pastEvents.hasStutteringJudgeRequestedVote = !!votePlays.find(votePlay => votePlay.hasStutteringJudgeRequestedVote);
},
fillWitchPotionsUsage() {
async fillWitchPotionsUsage() {
this.loadings.pastEvents = true;
const usePotionsQueryStrings = { "play-source": "witch", "play-action": "use-potion" };
const { data } = await this.$werewolvesAssistantAPI.getGameHistory(this.game._id, usePotionsQueryStrings);
const usePotionPlays = data.map(gameHistoryEntry => new GameHistory(gameHistoryEntry));
this.pastEvents.hasWitchUsedLifePotion = !!usePotionPlays.find(({ didWitchUsedLifePotion }) => didWitchUsedLifePotion);
this.pastEvents.hasWitchUsedDeathPotion = !!usePotionPlays.find(({ didWitchUsedDeathPotion }) => didWitchUsedDeathPotion);
},
fillLastGuardTarget() {
async fillLastGuardTarget() {
this.loadings.pastEvents = true;
const protectQueryStrings = { "play-source": "guard", "play-action": "protect" };
const { data } = await this.$werewolvesAssistantAPI.getGameHistory(this.game._id, protectQueryStrings);
if (data.length) {
const lastProtectPlay = new GameHistory(data[data.length - 1]);
this.pastEvents.lastGuardTarget = lastProtectPlay.play.targets[0].player;
}
},
async getPastEvents() {
const { firstWaiting, stutteringJudgePlayer, vileFatherOfWolvesPlayer } = this.game;
Expand All @@ -122,6 +133,7 @@ export default {
}
this.cantGetPastEvents = false;
} catch (err) {
console.log(err);
this.cantGetPastEvents = true;
this.$error.display(err);
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@
<ul id="potion-tabs" class="nav nav-pills nav-fill">
<li id="life-potion-tab" class="nav-item" @click="openLifePotionPanel">
<a id="use-life-potion-tab" class="nav-link"
:class="{ active: panel === 'life-potion', disabled: pastEvents.hasWithUsedLifePotion }" href="#">
:class="{ active: panel === 'life-potion', disabled: pastEvents.hasWitchUsedLifePotion }" href="#">
<img :src="SVGs.lifePotionSVG" width="25" alt="Life Potion" class="mr-2"
:class="{ 'used-potion-svg': pastEvents.hasWithUsedLifePotion }"/>
:class="{ 'used-potion-svg': pastEvents.hasWitchUsedLifePotion }"/>
<span v-html="lifePotionPanelTabText"/>
</a>
</li>
<li id="death-potion-tab" class="nav-item" @click="openDeathPotionPanel">
<a id="use-death-potion-tab" class="nav-link"
:class="{ active: panel === 'death-potion', disabled: pastEvents.hasWithUsedDeathPotion }" href="#">
:class="{ active: panel === 'death-potion', disabled: pastEvents.hasWitchUsedDeathPotion }" href="#">
<img :src="SVGs.deathPotionSVG" width="25" alt="Death Potion" class="mr-2"
:class="{ 'used-potion-svg': pastEvents.hasWithUsedDeathPotion }"/>
:class="{ 'used-potion-svg': pastEvents.hasWitchUsedDeathPotion }"/>
<span v-html="deathPotionPanelTabText"/>
</a>
</li>
Expand Down Expand Up @@ -98,8 +98,8 @@ export default {
return hasWitchUsedLifePotion ? this.$t("UsePotionPlayField.lifePotionUsed") : this.$t("UsePotionPlayField.useLifePotionOn");
},
deathPotionPanelTabText() {
const { hasWithUsedDeathPotion } = this.pastEvents;
return hasWithUsedDeathPotion ? this.$t("UsePotionPlayField.deathPotionUsed") : this.$t("UsePotionPlayField.useDeathPotionOn");
const { hasWitchUsedDeathPotion } = this.pastEvents;
return hasWitchUsedDeathPotion ? this.$t("UsePotionPlayField.deathPotionUsed") : this.$t("UsePotionPlayField.useDeathPotionOn");
},
alivePlayersWithoutWerewolvesTarget() {
return this.game.alivePlayers.filter(player => !player.hasAttribute("eaten"));
Expand All @@ -117,8 +117,8 @@ export default {
}
},
openDeathPotionPanel() {
const { hasWithUsedDeathPotion } = this.pastEvents;
if (!hasWithUsedDeathPotion) {
const { hasWitchUsedDeathPotion } = this.pastEvents;
if (!hasWitchUsedDeathPotion) {
this.panel = "death-potion";
scrollTo("#death-potion-tab", 500, { container: "#game-content-play-field" });
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div id="vote-play-field">
<div id="vote-play-field" class="d-flex flex-column">
<GamePlayAlerts :past-events="pastEvents"/>
<div v-if="game.stutteringJudgePlayer && game.stutteringJudgePlayer.isAlive">
<div class="row align-items-center">
Expand All @@ -15,7 +15,7 @@
<hr class="my-2 bg-dark"/>
</div>
<h5 id="targetable-players-text" class="text-center py-1" v-html="targetablePlayersText"/>
<PlayerVotes :play="play" :targetable-players="targetablePlayers" class="h-100" @player-votes="playerVotes"/>
<PlayerVotes :play="play" :targetable-players="targetablePlayers" class="flex-grow-1" @player-votes="playerVotes"/>
</div>
</template>

Expand Down
9 changes: 8 additions & 1 deletion src/components/Game/GameWinners/GameWinners.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,14 @@ import GameResult from "@/components/shared/Game/GameResult/GameResult";
export default {
name: "GameWinners",
components: { GameResult, GameSummaryButton, GameReviewButton, GameReviewModal, GameSummaryModal, PlayerCard },
computed: { ...mapGetters("game", { game: "game" }) },
computed: {
...mapGetters("game", { game: "game" }),
...mapGetters("audioManager", { audioManager: "audioManager" }),
},
created() {
this.audioManager.stopNightMusic();
this.audioManager.stopDayMusic();
},
methods: {
confirmRestartGame() {
return Swal.fire({
Expand Down
2 changes: 2 additions & 0 deletions src/components/shared/Game/GameResult/GameResult.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import eaten from "@/assets/svg/attributes/eaten.svg";
import inLove from "@/assets/svg/attributes/in-love.svg";
import villager from "@/assets/svg/roles/villager.svg";
import charmed from "@/assets/svg/attributes/charmed.svg";
import whiteWerewolf from "@/assets/svg/roles/white-werewolf.svg";
export default {
name: "GameResult",
Expand All @@ -29,6 +30,7 @@ export default {
"villagers": villager,
"lovers": inLove,
"pied-piper": charmed,
"white-werewolf": whiteWerewolf,
};
return winners[this.game.won.by] ? winners[this.game.won.by] : dead;
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import vote from "@/assets/svg/actions/vote.svg";
import deathPotion from "@/assets/svg/attributes/drank-death-potion.svg";
import shoot from "@/assets/svg/actions/shoot.svg";
import inLove from "@/assets/svg/attributes/in-love.svg";
import whiteWerewolf from "@/assets/svg/roles/white-werewolf.svg";
import Player from "@/classes/Player";
export default {
Expand All @@ -44,6 +45,7 @@ export default {
"all": { vote },
"werewolves": { eat: eaten },
"big-bad-wolf": { eat: bigBadWolf },
"white-werewolf": { eat: whiteWerewolf },
"witch": { "use-potion": deathPotion },
"hunter": { shoot },
"cupid": { charm: inLove },
Expand Down
Loading

0 comments on commit e4c4bd5

Please sign in to comment.