@@ -361,6 +372,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);
diff --git a/src/components/Player.vue b/src/components/Player.vue
index 697d375..9034528 100644
--- a/src/components/Player.vue
+++ b/src/components/Player.vue
@@ -45,17 +45,33 @@
+
+
{{ nominee.name }}!
-
+
{{ voters.length }} {{ locale.vote.votes }}
+
+ ? {{ locale.vote.votes }}
+
{{ locale.vote.inFavor }}
({{ locale.vote.majorityIs }} {{ Math.ceil(alive / 2) }})
diff --git a/src/components/modals/VoteHistoryModal.vue b/src/components/modals/VoteHistoryModal.vue
index 2e26bf1..9e05320 100644
--- a/src/components/modals/VoteHistoryModal.vue
+++ b/src/components/modals/VoteHistoryModal.vue
@@ -65,7 +65,7 @@
{{ vote.nominee }} |
{{ vote.type }} |
- {{ vote.votes.length }}
+ {{ vote.votes == null ? "?" : vote.votes.length }}
|
@@ -73,12 +73,12 @@
|
- {{ vote.votes.join(", ") }}
+ {{ vote.votes == null ? locale.modal.voteHistory.hiddenVote : vote.votes.join(", ") }}
|
diff --git a/src/main.js b/src/main.js
index 5357881..53b8c72 100644
--- a/src/main.js
+++ b/src/main.js
@@ -30,6 +30,7 @@ const faIcons = [
"Image",
"Link",
"MinusCircle",
+ "MinusSquare",
"Music",
"PeopleArrows",
"PlusCircle",
diff --git a/src/store/index.js b/src/store/index.js
index 885f300..d8d71dc 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -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;
},
diff --git a/src/store/locale/en/hatred.json b/src/store/locale/en/hatred.json
index a30bb1c..86ac4ce 100644
--- a/src/store/locale/en/hatred.json
+++ b/src/store/locale/en/hatred.json
@@ -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."
+ }
+ ]
}
]
diff --git a/src/store/locale/en/roles.json b/src/store/locale/en/roles.json
index 238966e..87f8a1b 100644
--- a/src/store/locale/en/roles.json
+++ b/src/store/locale/en/roles.json
@@ -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",
diff --git a/src/store/locale/en/ui.json b/src/store/locale/en/ui.json
index 39eb349..a3c0216 100644
--- a/src/store/locale/en/ui.json
+++ b/src/store/locale/en/ui.json
@@ -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"
}
}
}
diff --git a/src/store/locale/fr/hatred.json b/src/store/locale/fr/hatred.json
index ad644ec..3a73cfd 100644
--- a/src/store/locale/fr/hatred.json
+++ b/src/store/locale/fr/hatred.json
@@ -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."
+ }
+ ]
}
]
diff --git a/src/store/locale/fr/roles.json b/src/store/locale/fr/roles.json
index f8c1a06..d1157df 100644
--- a/src/store/locale/fr/roles.json
+++ b/src/store/locale/fr/roles.json
@@ -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",
diff --git a/src/store/locale/fr/ui.json b/src/store/locale/fr/ui.json
index 9fb0129..b0495a9 100644
--- a/src/store/locale/fr/ui.json
+++ b/src/store/locale/fr/ui.json
@@ -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"
}
}
}
diff --git a/src/store/modules/session.js b/src/store/modules/session.js
index 884117a..06d585f 100644
--- a/src/store/modules/session.js
+++ b/src/store/modules/session.js
@@ -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,15 +81,17 @@ 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
+ votes: organGrinder && state.isSpectator ? null :
+ players
.filter((player, index) => state.votes[index])
.map(({ name }) => name)
});
diff --git a/src/store/socket.js b/src/store/socket.js
index 36b3e9d..d38a24f 100644
--- a/src/store/socket.js
+++ b/src/store/socket.js
@@ -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,
@@ -724,6 +731,14 @@ class LiveSession {
if (this._isSpectator) return;
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;