Merge branch 'develop' into main

This commit is contained in:
Pingumask 2023-05-09 18:33:15 +00:00
commit 9427d9cc58
16 changed files with 204 additions and 14 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

View file

@ -28,6 +28,7 @@ export default {
gradients: [
["demon", "#ce0100", "#000"],
["townsfolk", "#1f65ff", "#000"],
["minion", "#ff6900", "#000"],
["default", "#4E4E4E", "#000"]
]
};

View file

@ -70,6 +70,17 @@
<template>{{ locale.menu.grimoire.ringBell }}</template>
<em>[B]</em>
</li>
<li @click="toggleOrganVoteMode" v-if="!session.isSpectator">
{{ locale.menu.grimoire.organGrinder }}
<em>
<font-awesome-icon
:icon="[
'fas',
grimoire.isOrganVoteMode ? 'check-square' : 'square'
]"
/>
</em>
</li>
<li @click="toggleNightOrder" v-if="players.length">
{{ locale.menu.grimoire.order }}
<em>
@ -382,6 +393,9 @@ export default {
this.$store.commit("session/setMarkedPlayer", -1);
}
},
toggleOrganVoteMode() {
this.$store.commit("toggleOrganVoteMode");
},
toggleRinging() {
this.$store.commit("toggleRinging", true);
setTimeout(this.$store.commit, 4000, "toggleRinging", false);

View file

@ -45,17 +45,49 @@
<!-- Overlay icons -->
<div class="overlay">
<font-awesome-icon
v-if="
!grimoire.isOrganVoteMode ||
!session.isSpectator ||
player.id == session.playerId
"
icon="hand-paper"
class="vote"
:title="locale.player.handUp"
@click="vote()"
/>
<font-awesome-icon
v-if="
grimoire.isOrganVoteMode &&
session.isSpectator &&
player.id !== session.playerId
"
icon="question"
class="vote"
:title="locale.player.handUp"
@click="vote()"
/>
<font-awesome-icon
v-if="
!grimoire.isOrganVoteMode ||
!session.isSpectator ||
player.id == session.playerId
"
icon="times"
class="vote"
:title="locale.player.handDown"
@click="vote()"
/>
<font-awesome-icon
v-if="
grimoire.isOrganVoteMode &&
session.isSpectator &&
player.id !== session.playerId
"
icon="question"
class="vote"
:title="locale.player.handDown"
@click="vote()"
/>
<font-awesome-icon
icon="times-circle"
class="cancel"
@ -559,11 +591,16 @@ export default {
&.fa-times * {
fill: url(#townsfolk);
}
&.fa-question * {
fill: url(#minion);
}
}
}
// other player voted yes, but is not locked yet
#townsquare.vote .player.vote-yes .overlay svg.vote.fa-hand-paper {
#townsquare.vote .player.vote-yes .overlay svg.vote.fa-hand-paper,
#townsquare.vote .player.vote-yes .overlay svg.vote.fa-question,
#townsquare.vote .player:not(.vote-yes) .overlay svg.vote.fa-question {
opacity: 0.5;
transform: scale(1);
}
@ -571,7 +608,13 @@ export default {
// you voted yes | a locked vote yes | a locked vote no
#townsquare.vote .player.you.vote-yes .overlay svg.vote.fa-hand-paper,
#townsquare.vote .player.vote-lock.vote-yes .overlay svg.vote.fa-hand-paper,
#townsquare.vote .player.vote-lock:not(.vote-yes) .overlay svg.vote.fa-times {
#townsquare.vote .player.vote-lock:not(.vote-yes) .overlay svg.vote.fa-times,
#townsquare.vote .player.you.vote-yes .overlay svg.vote.fa-question,
#townsquare.vote .player.vote-lock.vote-yes .overlay svg.vote.fa-question,
#townsquare.vote
.player.vote-lock:not(.vote-yes)
.overlay
svg.vote.fa-question {
opacity: 1;
transform: scale(1);
}

View file

@ -10,7 +10,17 @@
<em>{{ nominee.name }}</em
>!
<br />
<em class="blue"> {{ voters.length }} {{ locale.vote.votes }} </em>
<em
class="blue"
v-if="
!grimoire.isOrganVoteMode ||
nominee.role.team == 'traveler' ||
!session.isSpectator
"
>
{{ voters.length }} {{ locale.vote.votes }}
</em>
<em class="blue" v-else> ? {{ locale.vote.votes }} </em>
{{ locale.vote.inFavor }}
<em v-if="nominee.role.team !== 'traveler'">
({{ locale.vote.majorityIs }} {{ Math.ceil(alive / 2) }})

View file

@ -65,7 +65,7 @@
<td>{{ vote.nominee }}</td>
<td>{{ vote.type }}</td>
<td>
{{ vote.votes.length }}
{{ vote.votes == null ? "?" : vote.votes.length }}
<font-awesome-icon icon="hand-paper" />
</td>
<td>
@ -73,12 +73,20 @@
<font-awesome-icon
:icon="[
'fas',
vote.votes.length >= vote.majority ? 'check-square' : 'square'
vote.votes == null
? 'minus-square'
: vote.votes.length >= vote.majority
? 'check-square'
: 'square'
]"
/>
</td>
<td>
{{ vote.votes.join(", ") }}
{{
vote.votes == null
? locale.modal.voteHistory.hiddenVote
: vote.votes.join(", ")
}}
</td>
</tr>
</tbody>

View file

@ -30,6 +30,7 @@ const faIcons = [
"Image",
"Link",
"MinusCircle",
"MinusSquare",
"Music",
"PeopleArrows",
"PlusCircle",

View file

@ -111,6 +111,7 @@ export default new Vuex.Store({
isMuted: false,
isImageOptIn: false,
isStreamerMode: false,
isOrganVoteMode: false,
zoom: 0,
background: "",
timer: {
@ -185,6 +186,7 @@ export default new Vuex.Store({
toggleGrimoire: toggle("isPublic"),
toggleImageOptIn: toggle("isImageOptIn"),
toggleStreamerMode: toggle("isStreamerMode"),
toggleOrganVoteMode: toggle("isOrganVoteMode"),
setTimer(state, timer) {
state.grimoire.timer = timer;
},

View file

@ -372,5 +372,30 @@
"reason": "If the Lleech has poisoned the Heretic then the Lleech dies, the Heretic remains poisoned."
}
]
},
{
"id": "Organ Grinder",
"hatred": [
{
"id": "Butler",
"reason": "If the Organ Grinder is causing eyes closed voting, the Butler may raise their hand to vote but their vote is only counted if their master voted too."
},
{
"id": "Flowergirl",
"reason": "If players' eyes were closed during the nominations, the Flowergirl learns how many times the Demon voted."
},
{
"id": "Lil' Monsta",
"reason": "Votes for the Organ Grinder count if the Organ Grinder is babysitting Lil' Monsta."
},
{
"id": "Minstrel",
"reason": "Only 1 jinxed character can be in play. Evil players start knowing which player and character it is."
},
{
"id": "Preacher",
"reason": "Only 1 jinxed character can be in play. Evil players start knowing which player and character it is."
}
]
}
]

View file

@ -1637,6 +1637,20 @@
"setup": false,
"ability": "If you are executed, all but 3 players die. 1 minute later, the player with the most players pointing at them dies."
},
{
"id": "organgrinder",
"name": "Organ Grinder",
"edition": "",
"team": "minion",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 0,
"otherNightReminder": "",
"reminders": ["About to die",
"Used vote"],
"setup": false,
"ability": "All players keep their eyes closed when voting & the vote tally is secret. Votes for you only count if you vote."
},
{
"id": "lilmonsta",
"name": "Lil' Monsta",

View file

@ -13,7 +13,8 @@
"streamerMode": "Streamer Mode",
"animations": "Disable Animations",
"mute": "Mute Sounds",
"ringBell": "Ring Bell"
"ringBell": "Ring Bell",
"organGrinder ": "Organ Grinder Vote"
},
"session":{
"title":{
@ -238,7 +239,8 @@
"type": "Type",
"votes": "Votes",
"majority": "Majority",
"voters": "Voters"
"voters": "Voters",
"hiddenVote": "The result is hidden because of the Organ Grinder"
}
}
}

View file

@ -359,5 +359,30 @@
"reason": "Si le Tueur tire sur l'hôte de la Sangsue, l'hôte meurt. "
}
]
},
{
"id": "Organ Grinder",
"hatred": [
{
"id": "Butler",
"reason": "Si les votes ont lieu à bulletin secret à cause de l'Organiste, le Majordome peut lever sa main mais son vote ne compte que si son maître la lève aussi."
},
{
"id": "Flowergirl",
"reason": "Si les votes ont eu lieu à bulletin secret, la Fleuriste apprend combien de fois le Démon a voté."
},
{
"id": "Lil' Monsta",
"reason": "Les votes contre l'Organsite comptent si l'Organiste baby-sitte le Bébé Monstre."
},
{
"id": "Minstrel",
"reason": "Un seul personnage maudit peut être en jeu à la fois. Les joueurs Mauvais commencent la partie en sachant de quel joueur et quel rôle il s'agit."
},
{
"id": "Preacher",
"reason": "Un seul personnage maudit peut être en jeu à la fois. Les joueurs Mauvais commencent la partie en sachant de quel joueur et quel rôle il s'agit."
}
]
}
]

View file

@ -1811,6 +1811,22 @@
"setup": false,
"ability": "Si vous êtes exécuté, tous les joueurs sauf 3 meurent. 1 minute plus tard, le joueur le plus accusé meurt."
},
{
"id": "organgrinder",
"name": "Organiste",
"edition": "",
"team": "minion",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 0,
"otherNightReminder": "",
"reminders": [
"Condamné",
"Vote utilisé"
],
"setup": false,
"ability": "Les votes ont lieu à bulletin secret. Vous ne pouvez être exécuté que si vous levez la main."
},
{
"id": "lilmonsta",
"name": "Bébé monstre",

View file

@ -13,7 +13,8 @@
"streamerMode": "Mode Streamer",
"animations": "Effets réduits",
"mute": "Silencieux",
"ringBell": "Sonner Clocher"
"ringBell": "Sonner Clocher",
"organGrinder": "Vote d'Organiste"
},
"session":{
"title":{
@ -238,7 +239,8 @@
"type": "Type",
"votes": "Voix",
"majority": "Majorité",
"voters": "Votants"
"voters": "Votants",
"hiddenVote": "Résultat caché par l'Organiste"
}
}
}

View file

@ -1,3 +1,5 @@
import gameInfo from "../index.js";
/**
* Handle a vote request.
* If the vote is from a seat that is already locked, ignore it.
@ -71,6 +73,7 @@ const mutations = {
/**
* Create an entry in the vote history log. Requires current player array because it might change later in the game.
* Only stores votes that were completed.
* If the Organ Grinder is active, save the votes only for the Story Teller
* @param state
* @param players
*/
@ -78,17 +81,23 @@ const mutations = {
if (!state.isVoteHistoryAllowed && state.isSpectator) return;
if (!state.nomination || state.lockedVote <= players.length) return;
const isExile = players[state.nomination[1]].role.team === "traveler";
const organGrinder = gameInfo.state.grimoire.isOrganVoteMode && !isExile;
state.voteHistory.push({
timestamp: new Date(),
nominator: players[state.nomination[0]].name,
nominee: players[state.nomination[1]].name,
type: isExile ? "Exile" : "Execution",
type: isExile
? "Exile"
: "Execution" + (organGrinder && !state.isSpectator ? "*" : ""),
majority: Math.ceil(
players.filter(player => !player.isDead || isExile).length / 2
),
votes: players
.filter((player, index) => state.votes[index])
.map(({ name }) => name)
votes:
organGrinder && state.isSpectator
? null
: players
.filter((player, index) => state.votes[index])
.map(({ name }) => name)
});
},
clearVoteHistory(state) {

View file

@ -176,6 +176,10 @@ class LiveSession {
if (!this._isSpectator) return;
this._store.commit("toggleNight", params);
break;
case "isOrganVoteMode":
if (!this._isSpectator) return;
this._store.commit("toggleOrganVoteMode", params);
break;
case "isRinging":
if (!this._isSpectator) return;
this._store.commit("toggleRinging", params);
@ -288,6 +292,7 @@ class LiveSession {
isRinging: grimoire.isRinging,
timer: grimoire.timer,
isVoteHistoryAllowed: session.isVoteHistoryAllowed,
isOrganVoteMode: grimoire.isOrganVoteMode,
nomination: session.nomination,
votingSpeed: session.votingSpeed,
lockedVote: session.lockedVote,
@ -312,6 +317,7 @@ class LiveSession {
isNight,
isVoteHistoryAllowed,
isRinging,
isOrganVoteMode,
timer,
nomination,
votingSpeed,
@ -368,6 +374,7 @@ class LiveSession {
this._store.commit("toggleRinging", !!isRinging);
this._store.commit("toggleNight", !!isNight);
this._store.commit("session/setVoteHistoryAllowed", isVoteHistoryAllowed);
this._store.commit("toggleOrganVoteMode", !!isOrganVoteMode);
this._store.commit("session/nomination", {
nomination,
votes,
@ -725,6 +732,14 @@ class LiveSession {
this._send("isRinging", this._store.state.grimoire.isRinging);
}
/**
* Send the isOrganVoteMode status. ST only
*/
setIsOrganVoteMode() {
if (this._isSpectator) return;
this._send("isOrganVoteMode", this._store.state.grimoire.isOrganVoteMode);
}
/**
* Start or stop a timer
*/
@ -914,6 +929,9 @@ export default store => {
case "toggleNight":
session.setIsNight();
break;
case "toggleOrganVoteMode":
session.setIsOrganVoteMode();
break;
case "toggleRinging":
session.setIsRinging();
break;