Skip to content

Commit

Permalink
feat(Game): When players have to vote, the nominated player(s) have a…
Browse files Browse the repository at this point in the history
… mark on their role card. Closes #69
  • Loading branch information
antoinezanardi committed Nov 21, 2020
1 parent f943944 commit e8a44c8
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

* [#67](https://github.com/antoinezanardi/werewolves-assistant-web/issues/67) - Little Girl role implemented.
* [#68](https://github.com/antoinezanardi/werewolves-assistant-web/issues/68) - Villager-Villager role implemented.
* [#69](https://github.com/antoinezanardi/werewolves-assistant-web/issues/69) - When players have to vote, the nominated player(s) have a mark on their role card.
* [#72](https://github.com/antoinezanardi/werewolves-assistant-web/issues/72) - Travis CI linked to Slack.

### 🐛 Bug fixes
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ On this current version [![GitHub release](https://img.shields.io/github/release

- **<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/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/villager.png" width="25"/> The Villager-Villager**
- **<img src="https://werewolves-assistant-api.antoinezanardi.fr/img/roles/witch.png" width="25"/> The Witch**
- **<img src="https://werewolves-assistant-api.antoinezanardi.fr/img/roles/seer.png" width="25"/> The Seer**
- **<img src="https://werewolves-assistant-api.antoinezanardi.fr/img/roles/guard.png" width="25"/> The Guard**
- **<img src="https://werewolves-assistant-api.antoinezanardi.fr/img/roles/hunter.png" width="25"/> The Hunter**
- **<img src="https://werewolves-assistant-api.antoinezanardi.fr/img/roles/raven.png" width="25"/> The Raven**
- **<img src="https://werewolves-assistant-api.antoinezanardi.fr/img/roles/little-girl.png" width="25"/> The Little Girl**

Please check the <a href="https://werewolves-assistant-api.antoinezanardi.fr/apidoc/#player-roles" target="_blank">**Player role section on API documentation**</a> for more details about each role.
Please check the <a href="https://werewolves-assistant-api.antoinezanardi.fr/apidoc/#player-roles" target="_blank">**Player role section on API documentation**</a> or the <a href="https://werewolves-assistant.antoinezanardi.fr/about" target="_blank">**Available Roles section on the official website**</a> for more details about each role.

## <a name="versions">📈 Versions & changelog</a>
Each change when a new version comes up is listed in the <a href="https://github.com/antoinezanardi/werewolves-assistant-web/blob/master/CHANGELOG.md" target="_blank">CHANGELOG.md file</a> placed at project's root.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div id="elect-sheriff-play-field">
<PlayerVotes class="h-100" @player-votes="playerVotes"/>
<PlayerVotes class="h-100" :play="play" @player-votes="playerVotes"/>
</div>
</template>

Expand All @@ -10,6 +10,12 @@ import PlayerVotes from "@/components/shared/Game/PlayerVotes/PlayerVotes";
export default {
name: "ElectSheriffPlayField",
components: { PlayerVotes },
props: {
play: {
type: Object,
required: true,
},
},
methods: {
playerVotes(vote) {
this.$emit("player-votes", vote);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div id="game-content-play-field">
<transition name="fade" mode="out-in">
<ElectSheriffPlayField v-if="game.firstWaiting.to === 'elect-sheriff'" key="elect-sheriff"
<ElectSheriffPlayField v-if="game.firstWaiting.to === 'elect-sheriff'" key="elect-sheriff" :play="play"
class="h-100 container-fluid" @player-votes="playerVotes"/>
<LookPlayField v-else-if="game.firstWaiting.to === 'look'" key="look" :play="play"
class="h-100 container-fluid" @player-selected="playerSelected"/>
Expand All @@ -13,7 +13,7 @@
class="h-100 container-fluid" @player-selected="playerSelected"/>
<MarkPlayField v-else-if="game.firstWaiting.to === 'mark'" key="mark" :play="play"
class="h-100 container-fluid" @player-selected="playerSelected"/>
<VotePlayField v-else-if="game.firstWaiting.to === 'vote'" key="vote"
<VotePlayField v-else-if="game.firstWaiting.to === 'vote'" key="vote" :play="play"
class="h-100 container-fluid" @player-votes="playerVotes"/>
<SettleVotesPlayField v-else-if="game.firstWaiting.to === 'settle-votes'" key="settle-votes"
:play="play" class="h-100 container-fluid" @player-selected="playerSelected"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
<template>
<div id="vote-play-field">
<PlayerVotes class="h-100" @player-votes="playerVotes"/>
<PlayerVotes :play="play" class="h-100" @player-votes="playerVotes"/>
</div>
</template>

<script>
import PlayerVotes from "../../../../shared/Game/PlayerVotes/PlayerVotes";
import PlayerVotes from "@/components/shared/Game/PlayerVotes/PlayerVotes";
export default {
name: "VotePlayField",
components: { PlayerVotes },
props: {
play: {
type: Object,
required: true,
},
},
methods: {
playerVotes(vote) {
this.$emit("player-votes", vote);
Expand Down
6 changes: 5 additions & 1 deletion src/components/shared/Game/PlayerCard.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div ref="playerCard" class="player-card d-flex flex-column align-items-center w-100"
:class="{ 'selectable': selectable, 'selected': selected }">
<PlayerThumbnail ref="playerThumbnail" :player="player" :size="size"
<PlayerThumbnail ref="playerThumbnail" :player="player" :size="size" :is-nominated="isNominated"
:class="{ 'player-card-thumbnail-selected': selected }" @unset-player="unsetPlayer"
@player-selected="togglePlayerSelected"/>
<div class="player-card-name text-center" :class="{ 'player-card-name-lg': size === 'lg' }"
Expand Down Expand Up @@ -41,6 +41,10 @@ export default {
type: Boolean,
default: false,
},
isNominated: {
type: Boolean,
default: false,
},
},
computed: { ...mapGetters("game", { game: "game" }) },
methods: {
Expand Down
29 changes: 29 additions & 0 deletions src/components/shared/Game/PlayerThumbnail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
<span class="player-card-thumbnail" :class="{ 'player-card-thumbnail-lg': size === 'lg', 'dead-player-card': player.isAlive === false }">
<i v-if="!game._id" v-tooltip="$t('PlayerThumbnail.unsetPlayer')" class="fa fa-times-circle unset-player-button"
@click="unsetPlayer"/>
<transition name="fade" mode="out-in">
<img v-if="nominatedImageSource" v-tooltip="nominatedTooltipText"
class="nominated-player animate__animated animate__infinite animate__heartBeat animate__slow"
:src="nominatedImageSource" alt="Nominated Player"/>
</transition>
<VueFlip v-model="flipped" v-tooltip="playerThumbnailTooltip" height="100%" width="100%" @click.native="$emit('player-selected')">
<template #front>
<RoleImage :role="thumbnail.front"/>
Expand Down Expand Up @@ -30,6 +35,10 @@ export default {
type: String,
default: "md",
},
isNominated: {
type: Boolean,
default: false,
},
},
data() {
return {
Expand All @@ -48,6 +57,16 @@ export default {
}
return this.$t("PlayerThumbnail.chooseRole");
},
nominatedImageSource() {
const nominatedImageSources = {
"elect-sheriff": require("@/assets/svg/attributes/sheriff.svg"),
"vote": require("@/assets/svg/actions/vote.svg"),
};
return this.isNominated ? nominatedImageSources[this.game.firstWaiting.to] : undefined;
},
nominatedTooltipText() {
return this.isNominated ? this.$t(`PlayerThumbnail.nominated.${this.game.firstWaiting.to}`) : undefined;
},
},
watch: {
"player.role.current"(newRole, oldRole) {
Expand Down Expand Up @@ -121,4 +140,14 @@ export default {
right: -15px;
top: -15px;
}
.nominated-player {
cursor: pointer;
position: absolute;
right: -15px;
top: -15px;
width: 30px;
height: 30px;
z-index: 10;
}
</style>
13 changes: 11 additions & 2 deletions src/components/shared/Game/PlayerVotes/PlayerVote.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<template>
<div class="player-vote d-flex flex-column align-items-center p-2">
<PlayerCard :player="player"/>
<PlayerCard :player="player" :is-nominated="isNominated"/>
<div class="mb-3 vote-for-text text-center">
<span class="font-italic" v-html="$t('PlayerVote.voteFor')"/>
</div>
<VSelect :options="targetablePlayers" :placeholder="$t('PlayerVote.none')" :filter-by="filterBy"
label="name" @input="playerVotes">
<template #selected-option="{ role, name }">
<RoleImage :role="role.current" class="role-image-option mr-2"/>
<span v-html="name"/>
<span class="text-truncate" v-html="name"/>
</template>
<template #option="{ role, name }">
<RoleImage :role="role.current" class="role-image-option mr-2"/>
Expand All @@ -27,6 +27,7 @@ import { mapGetters } from "vuex";
import Player from "@/classes/Player";
import PlayerCard from "../PlayerCard";
import RoleImage from "../Role/RoleImage";
import { getNominatedPlayers } from "@/helpers/functions/Player";
export default {
name: "PlayerVote",
Expand All @@ -36,12 +37,20 @@ export default {
type: Player,
required: true,
},
play: {
type: Object,
required: true,
},
},
computed: {
...mapGetters("game", { game: "game" }),
targetablePlayers() {
return this.game.alivePlayers.filter(({ name }) => name !== this.player.name);
},
isNominated() {
const nominatedPlayers = getNominatedPlayers(this.play.votes, this.game, this.game.firstWaiting.to);
return nominatedPlayers ? !!nominatedPlayers.find(({ _id }) => _id === this.player._id) : undefined;
},
},
methods: {
filterBy(option, label, search) {
Expand Down
8 changes: 7 additions & 1 deletion src/components/shared/Game/PlayerVotes/PlayerVotes.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div id="player-votes" class="row justify-content-center align-items-center">
<PlayerVote v-for="player in game.alivePlayers" :key="player.name" :player="player"
<PlayerVote v-for="player in game.alivePlayers" :key="player.name" :player="player" :play="play"
class="col-6 col-lg-3" @player-votes="playerVotes"/>
</div>
</template>
Expand All @@ -12,6 +12,12 @@ import PlayerVote from "./PlayerVote";
export default {
name: "PlayerVotes",
components: { PlayerVote },
props: {
play: {
type: Object,
required: true,
},
},
computed: { ...mapGetters("game", { game: "game" }) },
methods: {
playerVotes(vote) {
Expand Down
9 changes: 7 additions & 2 deletions src/helpers/functions/Player.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ function incrementPlayerVoteCount(votedPlayers, playerId, game, inc = 1) {

export function getNominatedPlayers(votes, game, action) {
const votedPlayers = [];
const sheriffPlayer = game.getPlayerWithAttribute("sheriff");
for (const vote of votes) {
incrementPlayerVoteCount(votedPlayers, vote.for, game);
if (action === "vote" && sheriffPlayer && sheriffPlayer._id === vote.from) {
incrementPlayerVoteCount(votedPlayers, vote.for, game, 2);
} else {
incrementPlayerVoteCount(votedPlayers, vote.for, game);
}
}
if (action === "vote") {
const ravenMarkedPlayer = game.getPlayerWithAttribute("raven-marked");
if (ravenMarkedPlayer.isAlive) {
if (ravenMarkedPlayer && ravenMarkedPlayer.isAlive) {
incrementPlayerVoteCount(votedPlayers, ravenMarkedPlayer._id, game, 2);
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/plugins/vue-i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,11 @@
},
"PlayerThumbnail": {
"chooseRole": "Choisir un rôle",
"unsetPlayer": "Retirer le joueur"
"unsetPlayer": "Retirer le joueur",
"nominated": {
"elect-sheriff": "Ce joueur est nominé pour devenir maire",
"vote": "Ce joueur est nominé pour la pendaison"
}
},
"PlayerVote": {
"voteFor": "Vote pour",
Expand Down

0 comments on commit e8a44c8

Please sign in to comment.