add 'on the block' indicator

- after vote, ST chooses to put onto block / empty block / no change to block
- player menu has add / remove from block
- players are automatically removed from the block when (i) they die (ii) another player is put onto block
- fixed crash on add/remove/etc player mid vote
This commit is contained in:
nicfreeman1209 2021-05-02 22:52:20 +01:00
parent 3ae36e2f0f
commit 943d228e98
8 changed files with 115 additions and 25 deletions

View File

@ -1,5 +1,7 @@
# Release Notes
- add 'on the block' indicator
### Version 2.12.0
- tweak reference sheet to better fit screen in single column layout
- add warning icon overlay for setup roles on character assignment modal

View File

@ -143,7 +143,7 @@
</template>
</template>
<template v-if="tab === 'players' && !session.isSpectator">
<template v-if="tab === 'players' && !session.isSpectator && !session.nomination">
<!-- Users -->
<li class="headline">Players</li>
<li @click="addPlayer" v-if="players.length < 20">Add<em>[A]</em></li>

View File

@ -97,6 +97,11 @@
@click="updatePlayer('isVoteless', true)"
title="Ghost vote"
/>
<font-awesome-icon
icon="crosshairs"
v-if="player.isOnBlock"
class="on-block"
/>
<div
class="name"
@click="isMenuOpen = !isMenuOpen"
@ -124,18 +129,28 @@
<li @click="changeName">
<font-awesome-icon icon="user-edit" />Rename
</li>
<li v-if="!session.nomination" @click="nominatePlayer()">
<font-awesome-icon icon="hand-point-right" />
Nomination
</li>
<li @click="movePlayer()">
<font-awesome-icon icon="redo-alt" />
Move player
</li>
<li @click="swapPlayer()">
<font-awesome-icon icon="exchange-alt" />
Swap seats
<li v-if="!session.nomination" @click="removePlayer">
<font-awesome-icon icon="times-circle" />
Remove
</li>
<template v-if="!session.nomination">
<li @click="movePlayer()">
<font-awesome-icon icon="redo-alt" />
Move player
</li>
<li @click="swapPlayer()">
<font-awesome-icon icon="exchange-alt" />
Swap seats
</li>
<li @click="toggleOnBlock()">
<font-awesome-icon icon="crosshairs" />
{{ player.isOnBlock ? "Take off block" : "Put on block" }}
</li>
<li @click="nominatePlayer()">
<font-awesome-icon icon="hand-point-right" />
Nomination
</li>
</template>
<li
@click="updatePlayer('id', '', true)"
v-if="player.id && session.sessionId"
@ -143,10 +158,6 @@
<font-awesome-icon icon="chair" />
Empty seat
</li>
<li @click="removePlayer">
<font-awesome-icon icon="times-circle" />
Remove
</li>
</template>
<li
@click="claimSeat"
@ -257,6 +268,9 @@ export default {
if (this.grimoire.isPublic) {
if (!this.player.isDead) {
this.updatePlayer("isDead", true);
if (this.player.isOnBlock) {
this.toggleOnBlock();
}
} else if (this.player.isVoteless) {
this.updatePlayer("isVoteless", false);
this.updatePlayer("isDead", false);
@ -265,6 +279,9 @@ export default {
}
} else {
this.updatePlayer("isDead", !this.player.isDead);
if (this.player.isOnBlock) {
this.toggleOnBlock();
}
if (this.player.isVoteless) {
this.updatePlayer("isVoteless", false);
}
@ -319,6 +336,10 @@ export default {
this.isMenuOpen = false;
this.$emit("trigger", ["claimSeat"]);
},
toggleOnBlock() {
this.isMenuOpen = false;
this.$emit("trigger", ["toggleOnBlock"]);
},
/**
* Allow the ST to override a locked vote.
*/
@ -578,10 +599,7 @@ li.move:not(.from) .player .overlay svg.move {
}
/****** Vote icon ********/
.player .has-vote {
position: absolute;
right: 2px;
margin-top: -15%;
.player .has-vote .on-block {
color: #fff;
filter: drop-shadow(0 0 3px black);
transition: opacity 250ms;
@ -593,6 +611,19 @@ li.move:not(.from) .player .overlay svg.move {
}
}
.has-vote {
position: absolute;
margin-top: -15%;
right: 2px;
}
.on-block {
position: absolute;
margin-top: -15%;
left: 3px;
color: darkred;
}
/****** Session seat glow *****/
@mixin glow($name, $color) {
@keyframes #{$name}-glow {

View File

@ -201,6 +201,13 @@ export default {
this.move = -1;
this.swap = -1;
this.nominate = -1;
},
toggleOnBlock(playerIndex) {
if (this.players[playerIndex].isOnBlock) {
this.$store.commit("players/setOnBlock", -1);
} else {
this.$store.commit("players/setOnBlock", playerIndex);
}
}
}
};

View File

@ -62,6 +62,19 @@
<div class="button demon" @click="finish">Close</div>
</div>
</template>
<template v-if="!session.isSpectator">
<div
class="button-group"
v-if="session.lockedVote && !session.isVoteInProgress"
>
<div class="button demon" @click="setOnBlock">
Put on block
</div>
<div class="button demon" @click="emptyBlock">
Empty block
</div>
</div>
</template>
<template v-else-if="canVote">
<div v-if="!session.isVoteInProgress">
{{ session.votingSpeed / 1000 }} seconds between votes
@ -235,6 +248,14 @@ export default {
if (speed > 0) {
this.$store.commit("session/setVotingSpeed", speed);
}
},
setOnBlock() {
this.$store.commit("players/setOnBlock", this.session.nomination[1]);
this.finish();
},
emptyBlock() {
this.$store.commit("players/setOnBlock", -1);
this.finish();
}
}
};

View File

@ -16,6 +16,7 @@ const faIcons = [
"CloudMoon",
"Cog",
"Copy",
"Crosshairs",
"Dice",
"Dragon",
"ExchangeAlt",

View File

@ -5,6 +5,7 @@ const NEWPLAYER = {
reminders: [],
isVoteless: false,
isDead: false,
isOnBlock: false,
pronouns: ""
};
@ -136,6 +137,14 @@ const mutations = {
move(state, [from, to]) {
state.players.splice(to, 0, state.players.splice(from, 1)[0]);
},
setOnBlock(state, playerIndex) {
state.players.forEach(player => {
player.isOnBlock = false;
});
if (playerIndex >= 0) {
state.players[playerIndex].isOnBlock = true;
}
},
setBluff(state, { index, role } = {}) {
if (index !== undefined) {
state.bluffs.splice(index, 1, role);

View File

@ -168,6 +168,10 @@ class LiveSession {
if (!this._isSpectator) return;
this._store.commit("players/remove", params);
break;
case "onBlock":
if (!this._isSpectator) return;
this._store.commit("players/setOnBlock", params);
break;
case "isNight":
if (!this._isSpectator) return;
this._store.commit("toggleNight", params);
@ -251,6 +255,7 @@ class LiveSession {
id: player.id,
isDead: player.isDead,
isVoteless: player.isVoteless,
isOnBlock: player.isOnBlock,
pronouns: player.pronouns,
...(player.role && player.role.team === "traveler"
? { roleId: player.role.id }
@ -312,12 +317,14 @@ class LiveSession {
const player = players[x];
const { roleId } = state;
// update relevant properties
["name", "id", "isDead", "isVoteless", "pronouns"].forEach(property => {
const value = state[property];
if (player[property] !== value) {
this._store.commit("players/update", { player, property, value });
["name", "id", "isDead", "isVoteless", "isOnBlock", "pronouns"].forEach(
property => {
const value = state[property];
if (player[property] !== value) {
this._store.commit("players/update", { player, property, value });
}
}
});
);
// roles are special, because of travelers
if (roleId && player.role.id !== roleId) {
const role =
@ -697,6 +704,15 @@ class LiveSession {
}
}
/**
* Set which player is on the block. ST only
* @param id, player id or -1 for empty
*/
setOnBlock(playerIndex) {
if (this._isSpectator) return;
this._send("onBlock", playerIndex);
}
/**
* Clear the vote history for everyone. ST only
*/
@ -849,6 +865,9 @@ export default store => {
case "players/setFabled":
session.sendFabled();
break;
case "players/setOnBlock":
session.setOnBlock(payload);
break;
case "players/swap":
session.swapPlayer(payload);
break;