added vote buttons

This commit is contained in:
Steffen 2020-06-03 22:25:23 +02:00
parent 952cb1f0a5
commit 31b4cd5183
No known key found for this signature in database
GPG Key ID: 764D74E98267DFC6
6 changed files with 144 additions and 19 deletions

View File

@ -7,7 +7,8 @@
{
dead: player.isDead,
'no-vote': player.isVoteless,
you: player.id === session.playerId
you: player.id === session.playerId,
'voted-yes': session.votes[index]
},
player.role.team
]"
@ -40,6 +41,12 @@
/>
<!-- Overlay icons -->
<font-awesome-icon
icon="skull"
class="vote"
title="Vote"
@click="vote()"
/>
<font-awesome-icon
icon="times-circle"
class="cancel"
@ -71,7 +78,7 @@
<!-- Ghost vote icon -->
<font-awesome-icon
icon="vote-yea"
class="vote"
class="has-vote"
v-if="player.isDead && !player.isVoteless"
@click="updatePlayer('isVoteless', true)"
title="Ghost vote"
@ -163,6 +170,9 @@ export default {
}
},
computed: {
index: function() {
return this.$store.state.players.players.indexOf(this.player);
},
...mapState(["grimoire", "session"]),
...mapGetters({ nightOrder: "players/nightOrder" })
},
@ -235,6 +245,10 @@ export default {
claimSeat() {
this.isMenuOpen = false;
this.$emit("trigger", ["claimSeat"]);
},
vote() {
if (this.player.id !== this.session.playerId) return;
this.$store.commit("session/vote", [this.index]);
}
}
};
@ -402,6 +416,7 @@ export default {
&.swap,
&.move,
&.nominate,
&.vote,
&.cancel {
top: 9%;
left: 20%;
@ -417,6 +432,17 @@ export default {
}
}
#townsquare.vote .player.voted-yes > svg.vote {
color: $demon;
opacity: 0.5;
transform: scale(1);
}
#townsquare.vote .player.you.voted-yes > svg.vote {
opacity: 1;
transform: scale(1);
}
li.from:not(.nominate) .player > svg.cancel {
opacity: 1;
transform: scale(1);
@ -432,7 +458,7 @@ li.move:not(.from) .player > svg.move {
}
/****** Vote icon ********/
.player .vote {
.player .has-vote {
position: absolute;
right: 2px;
bottom: 45px;

View File

@ -4,7 +4,8 @@
class="square"
v-bind:class="{
public: grimoire.isPublic,
spectator: session.isSpectator
spectator: session.isSpectator,
vote: session.nomination
}"
v-bind:style="{ zoom: grimoire.zoom }"
>

View File

@ -1,5 +1,5 @@
<template>
<div class="vote">
<div id="vote">
<div class="arrows">
<span class="nominee" :style="nomineeStyle"></span>
<span class="nominator" :style="nominatorStyle"></span>
@ -10,17 +10,29 @@
>!
<br />
<template v-if="nominee.role.team !== 'traveler'">
<em class="blue">{{ Math.ceil(alive / 2) }} votes</em> required for an
<em>execution</em>
<em class="blue">{{ Math.ceil(alive / 2) }} votes</em> required to
<em>execute</em>.
</template>
<template v-else>
<em>{{ Math.ceil(players.length / 2) }} votes</em> required for an
<em>exile</em>
<em>{{ Math.ceil(players.length / 2) }} votes</em> required to
<em>exile</em>.
</template>
<div class="button-group">
<div class="button-group" v-if="!session.isSpectator">
<div class="button">Start Vote</div>
<div class="button" @click="finish">Finish Vote</div>
</div>
<div
class="button-group"
v-else-if="
player && (!player.isVoteless || nominee.role.team === 'traveler')
"
>
<div class="button vote-no" @click="vote(false)">Vote NO</div>
<div class="button vote-yes" @click="vote(true)">Vote YES</div>
</div>
<div v-else-if="!player">
Please claim a seat to vote.
</div>
</div>
</div>
</template>
@ -54,6 +66,10 @@ export default {
transform: `rotate(${Math.round((nomination / players) * 360)}deg)`
};
},
player: function() {
const id = this.$store.state.session.playerId;
return this.$store.state.players.players.find(p => p.id === id);
},
...mapState("players", ["players"]),
...mapState(["session"]),
...mapGetters({ alive: "players/alive" })
@ -61,6 +77,12 @@ export default {
methods: {
finish() {
this.$store.commit("session/nomination", false);
},
vote(vote) {
const index = this.players.findIndex(p => p.id === this.session.playerId);
if (index >= 0 && !!this.session.votes[index] !== vote) {
this.$store.commit("session/vote", [index, vote]);
}
}
}
};
@ -69,7 +91,7 @@ export default {
<style lang="scss" scoped>
@import "../vars.scss";
.vote {
#vote {
position: absolute;
width: 20%;
z-index: 20;
@ -151,4 +173,30 @@ export default {
animation: arrow-cw 1s ease-out;
}
}
.button.vote-no {
background: radial-gradient(
at 0 -15%,
rgba(255, 255, 255, 0.07) 70%,
rgba(255, 255, 255, 0) 71%
)
0 0/80% 90% no-repeat content-box,
linear-gradient(#0031ad, rgba(5, 0, 0, 0.22)) content-box,
linear-gradient(#292929, #001142) border-box;
box-shadow: inset 0 1px 1px #002c9c, 0 0 10px #000;
&:hover {
color: #008cf7;
}
}
.button.vote-yes {
background: radial-gradient(
at 0 -15%,
rgba(255, 255, 255, 0.07) 70%,
rgba(255, 255, 255, 0) 71%
)
0 0/80% 90% no-repeat content-box,
linear-gradient(#ad0000, rgba(5, 0, 0, 0.22)) content-box,
linear-gradient(#292929, #420000) border-box;
box-shadow: inset 0 1px 1px #9c0000, 0 0 10px #000;
}
</style>

View File

@ -10,6 +10,7 @@ const faIcons = [
"BroadcastTower",
"Camera",
"CheckSquare",
"Skull",
"Cog",
"Copy",
"ExchangeAlt",

View File

@ -4,7 +4,9 @@ const state = () => ({
playerCount: 0,
playerId: "",
claimedSeat: -1,
nomination: false
nomination: false,
votes: [],
lockedVote: -1
});
const getters = {};
@ -29,6 +31,11 @@ const mutations = {
},
nomination(state, nomination) {
state.nomination = nomination;
state.votes = [];
},
vote(state, [index, vote]) {
state.votes = [...state.votes];
state.votes[index] = vote === undefined ? !state.votes[index] : vote;
}
};

View File

@ -99,6 +99,12 @@ class LiveSession {
case "ping":
this._handlePing(params);
break;
case "nomination":
this._store.commit("session/nomination", params);
break;
case "vote":
this._store.commit("session/vote", params);
break;
case "bye":
this._handleBye(params);
break;
@ -291,7 +297,7 @@ class LiveSession {
}
// remove claimed seats from players that are no longer connected
this._store.state.players.players.forEach(player => {
if (player.id && !this._players[player.id]) {
if (!this._isSpectator && player.id && !this._players[player.id]) {
this._store.commit("players/update", {
player,
property: "id",
@ -336,20 +342,50 @@ class LiveSession {
* @private
*/
_updateSeat([index, value]) {
if (this._isSpectator) return;
const property = "id";
const players = this._store.state.players.players;
// remove previous seat
const player = this._store.state.players.players.find(
({ id }) => id === value
);
if (player) {
this._store.commit("players/update", { player, property, value: "" });
const oldIndex = players.findIndex(({ id }) => id === value);
if (oldIndex >= 0 && oldIndex !== index) {
this._store.commit("players/update", {
player: players[oldIndex],
property,
value: ""
});
}
// add playerId to new seat
if (index >= 0) {
const player = this._store.state.players.players[index];
const player = players[index];
if (!player) return;
this._store.commit("players/update", { player, property, value });
}
// update player session list as if this was a ping
this._handlePing([true, value]);
}
/**
* A player nomination.
* @param nomination [nominator, nominee]
*/
nomination(nomination) {
if (this._isSpectator) return;
const players = this._store.state.players.players;
if (
!nomination ||
(players.length > nomination[0] && players.length > nomination[1])
) {
this._send("nomination", nomination);
}
}
/**
* Send a vote.
* @param index
*/
vote([index]) {
if (!this._isSpectator) return;
this._send("vote", [index, this._store.state.session.votes[index]]);
}
}
@ -371,6 +407,12 @@ module.exports = store => {
case "session/claimSeat":
session.claimSeat(payload);
break;
case "session/nomination":
session.nomination(payload);
break;
case "session/vote":
session.vote(payload);
break;
case "players/set":
case "players/swap":
case "players/move":