Compare commits

...

81 Commits

Author SHA1 Message Date
bra1n d9c2b17dc9 updated build script 2023-11-06 13:10:43 +01:00
bra1n fb40d98fd6 2.16.2 2023-11-06 13:06:21 +01:00
bra1n b87307193f 2.16.1 2023-11-06 13:06:15 +01:00
bra1n ece11dfcde script tool compatibility 2023-11-06 13:06:11 +01:00
bra1n 1c52b232c0 fix deploy 2023-04-21 15:32:11 +02:00
bra1n 55ea934304 package-lock update 2023-04-21 15:28:09 +02:00
Steffen d7e9647bf5
removed Deus ex Fiasco 2023-04-21 15:20:35 +02:00
Steffen 723974b3d3
Update README.md 2023-03-14 11:10:55 +01:00
Steffen beabcb14a4
Merge pull request #277 from ratteler50/patch-2
Updated night order for all roles
2022-10-21 09:45:08 +02:00
Dae Lorant 48cb4942a2
Removed otherNight order for pixie
It seems like pixie having an entry for otherNight was a bug in the script tool that will be fixed separately.  Removed pixie from night order and shifted all other roles back down one.
2022-10-20 11:21:09 -07:00
Dae Lorant a9724778a6
Updated changelog
Apparently changelog update is required for a pull request, so here is one :)
2022-10-12 21:21:15 -07:00
Dae Lorant 974bbb1a0f
Updated night order for all roles
Updated night order for all roles to match the order at https://script.bloodontheclocktower.com/data/nightsheet.json

Some noticeable changes:
- Legion was moved much earlier in the order of demons (relevant if a another demon is made in a legion game, you can keep it around and kill it with legion before it kills on a subsequent night)
- Amnesiac was moved much later in night order (a more reasonable place for the most common type of amni abilities)
- Magician was given a night order for N1
- Pixie was given a night order for other nights
2022-10-12 03:04:48 -07:00
Steffen 4c529472b8
Merge pull request #273 from Skateside/develop
Missing Jinxes
2022-09-25 22:27:50 +02:00
James Long 28cd156baa
Merge pull request #1 from Skateside/fix/missing-heretic-jinxes
Add missing jinxes
2022-09-22 14:52:06 +01:00
James Long 3a2ae90849
Add missing jinxes
There were 2 missing jinxes for the Heretic: Baron and Lleech - this adds them both in.
2022-09-22 14:51:07 +01:00
Steffen ea5b3c523f
philosopher updated 2022-09-14 15:43:22 +02:00
Steffen 54e224bba3
reverted moonchild 2022-08-30 10:16:47 +02:00
Steffen 5ca891e752
reverted some icons 2022-08-10 10:48:56 +02:00
Steffen f98b43e304
2.16.0 2022-06-14 14:56:50 +02:00
Steffen 2a66dfff4b
changelog 2022-06-14 14:56:44 +02:00
Steffen c77dd47397
Merge pull request #262 from alexanderfletcher/dev-3
Add ability to use json from clipboard to upload script
2022-06-14 14:47:52 +02:00
Alexander Fletcher 729869df51 Add ability to use json from clipboard to upload script 2022-05-30 19:40:40 +08:00
Steffen d0a117297c
beggar updated 2022-05-05 21:46:13 +02:00
Steffen 75dd02c6a3
added redirect to Chinese version 2022-04-08 11:02:13 +02:00
Steffen 4bd7ecbe03
Update README.md 2022-04-04 20:33:22 +02:00
Steffen 99f6b68fd7
2.15.4 2022-04-04 11:28:01 +02:00
Steffen 1c4ad9634a
changelog & npm audit 2022-04-04 11:27:55 +02:00
Steffen afd593d632
Merge pull request #253 from nathansferguson/reminder-flicker-153
Add static hover target to prevent add reminder token flickering (fix #153)
2022-04-04 11:25:41 +02:00
Nathan Ferguson 84f6cab2d8 Add static hover target to prevent reminder token flickering #153 2022-04-03 22:35:18 +12:00
Steffen 5af776bfbf
Merge pull request #252 from ratteler50/patch-1
Updated the Snitch/Marionette jinx
2022-04-01 09:21:39 +02:00
David Lorant dbb4c1a1ef
Updated the Snitch/Marionette jinx
This change was announced in Expansion-Chat on 03/18/2022

https://discord.com/channels/569683781800296501/696695228496871436/954305424096636948
2022-03-31 21:35:05 -07:00
Steffen 2b41f3145e
Update deploy.yml 2022-02-20 20:24:16 +01:00
Steffen 9575a8eca3
npm audit 2022-02-20 20:09:08 +01:00
Steffen 0bd590c80e
2.15.3 2022-02-20 20:06:28 +01:00
Steffen b9ae60c652
gamestate bug fixed and nightwatchman deploy 2022-02-20 20:05:01 +01:00
Steffen 4cbab79bae
script tool url fixed 2022-02-08 20:15:38 +01:00
Steffen d567335499
Delete codeql-analysis.yml 2022-02-05 23:17:43 +01:00
Steffen 1c63ee6208
Merge pull request #242 from eddgabriel/develop
Nightwatchman
2022-02-05 23:07:21 +01:00
eddgabriel 2a0f025b0c
Merge branch 'bra1n:develop' into develop 2022-02-05 21:18:27 +00:00
eddgabriel 11e1e99a94 Nightwatchman 2022-02-05 21:15:55 +00:00
Steffen a9eb07ad14
script tool url fixed 2022-01-30 12:12:51 +01:00
Steffen 350d2a5a18
fixed local server (closes #240) 2022-01-25 12:25:48 +01:00
Steffen 0ca33f0d53
Merge pull request #235 from eddgabriel/develop
Atheist
2021-12-07 14:02:18 +01:00
eddgabriel bf393bbc71 Update icons 2021-12-07 12:12:42 +00:00
eddgabriel a73d6ce73c Update roles.json 2021-12-07 10:17:17 +00:00
eddgabriel 31265aa4fd Atheist 2021-12-07 10:15:40 +00:00
Steffen a3cb8570f6
Merge pull request #233 from eddgabriel/develop
Psychopath
2021-11-19 20:42:25 +01:00
eddgabriel 8649aa4eec Psychopath 2021-11-18 22:11:35 +00:00
Steffen 9e6ff3e69e
fix jinx 2021-11-05 22:36:16 +01:00
Steffen ffe69a8dcb
Merge pull request #229 from eddgabriel/develop
Riot
2021-11-05 21:51:02 +01:00
eddgabriel 6a3fdfa384 Riot
Look at the number of those jinxes... Just look at 'em...
2021-11-04 22:14:44 +00:00
Steffen 83889b21dd
Merge pull request #227 from eddgabriel/develop
Engineer
2021-10-22 21:00:44 +02:00
eddgabriel c93b50df42 Engineer 2021-10-21 22:35:11 +01:00
Steffen 8a6da3d7ab
Update README.md 2021-10-19 10:46:15 +02:00
Steffen 7ebf296cfc
Merge pull request #224 from eddgabriel/develop
Alchemist!
2021-10-15 10:38:09 +02:00
eddgabriel 772c94a6c6 Alchemist! 2021-10-14 13:36:43 +01:00
Steffen 45dfb124f7
Merge pull request #221 from eddgabriel/develop
Puzzlemaster
2021-09-28 14:03:07 +02:00
eddgabriel 401312ab09 Puzzlemaster 2021-09-28 11:43:10 +01:00
Steffen c00b89824c
Merge pull request #216 from eddgabriel/develop
Fearmonger
2021-09-11 17:54:54 +02:00
eddgabriel 59c39773aa Update fearmonger.png 2021-09-11 15:40:39 +01:00
eddgabriel fa1feb3c0b Fearmonger 2021-09-10 00:07:12 +01:00
Steffen e1ba442af7
Merge pull request #214 from eddgabriel/develop
Golem
2021-08-31 20:08:42 +02:00
eddgabriel 5780c155d3 Merge branch 'develop' of https://github.com/eddgabriel/townsquare into develop 2021-08-31 10:22:47 +01:00
eddgabriel 9517a3e262 Golem 2021-08-31 10:20:33 +01:00
Steffen 18746ab642
npm audit 2021-08-19 20:54:55 +02:00
Steffen 29357ecf54
Merge pull request #210 from eddgabriel/develop
Al-Hadikhia
2021-08-13 13:02:50 +02:00
eddgabriel f664bdf024 Update roles.json 2021-08-13 11:56:59 +01:00
eddgabriel 9fff5541bb Al-Hadikhia 2021-08-12 23:21:28 +01:00
Steffen 0199108e2f
Merge pull request #204 from eddgabriel/develop
Noble
2021-08-02 11:46:52 +02:00
eddgabriel a35c6f3c14 Noble 2021-08-02 10:28:59 +01:00
Steffen 9bafcc2c61
Merge pull request #202 from eddgabriel/develop
Huntsman/Damsel
2021-07-21 12:34:13 +02:00
eddgabriel fb2e81c299 Huntsman/Damsel 2021-07-20 20:27:02 +01:00
Steffen af2587295d
2.15.2 2021-07-14 14:00:11 +02:00
Steffen 97121e81e7
changelog 2021-07-14 14:00:10 +02:00
Steffen 3d696c85de
fix negative nightOrder numbers causing a mess (fixes #193) 2021-07-14 14:00:10 +02:00
Steffen ff217761ff
revert role modal tab when closing (fixes #194) 2021-07-14 14:00:10 +02:00
Steffen 30aa5cdf8a
show leaves on tokens with global reminders 2021-07-14 14:00:10 +02:00
Steffen fe51d60839
added mobile web app capabilities 2021-07-14 14:00:10 +02:00
Steffen 282291e6ec
Merge pull request #198 from eddgabriel/develop
Futureproofing
2021-07-14 12:47:05 +02:00
eddgabriel 2a751b7fc2 Update CHANGELOG.md 2021-07-08 22:34:40 +01:00
eddgabriel 6fd7a0f0ee Futureproofing
So that when the name changes in the script tool, we're ready :)
2021-07-08 22:31:12 +01:00
43 changed files with 5848 additions and 17808 deletions

View File

@ -9,6 +9,8 @@ module.exports = {
},
rules: {
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off"
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
"vue/multi-word-component-names": "off",
"vue/no-reserved-component-names": "off",
}
};

View File

@ -1,67 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ main, develop ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main, develop ]
schedule:
- cron: '27 22 * * 1'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@ -5,19 +5,23 @@ on:
- main
jobs:
build-and-deploy:
concurrency: ci-${{ github.ref }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Checkout 🛎️
uses: actions/checkout@v2
- name: Build
run: |
npm install
npm run-script build
- uses: actions/setup-node@v2
with:
node-version: '18'
- name: Deploy
uses: JamesIves/github-pages-deploy-action@releases/v3
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BRANCH: gh-pages
FOLDER: dist
- name: Install and Build 🔧
run: |
npm ci
npm run build
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@v4.2.5
with:
branch: gh-pages
folder: dist

View File

@ -1,7 +1,43 @@
# Release Notes
### Version 2.16.2
- fixed custom script format to support new script tool JSON
- updated packages to be compatible with Node >= 18 again
---
### Version 2.16.1
- Updated character night order to be consistent with script tool
---
### Version 2.16.0
- Add ability to use json from clipboard to upload script (by @alexanderfletcher)
---
### Version 2.15.4
- fixed flickering of add reminder token
- added redirect to Chinese version
---
### Version 2.15.3
- add Huntsman/Damsel, Noble, Al-Hadikhia, Golem, Fearmonger, Puzzlemaster, Alchemist, Engineer, Riot, Psychopath, Atheist, Nightwatchman to list of available characters
- fixed game state JSON not handling custom Fabled correctly
---
### Version 2.15.2
- added mobile web application support
- show correct number of leaves on roles with global reminders
- fixed a bug with traveler list showing up when assigning demon bluffs
- fixed a bug with homebrew scripts that contained negative night order positions
---
### Version 2.15.1
- fix Mephit not showing up on scripts
- fix Mephit not showing up on scripts, futureproof Mephit name change
- add Boomdandy to list of available characters
---

View File

@ -1,5 +1,7 @@
# Blood on the Clocktower Grimoire & Town Square
> :warning: **This project is no longer actively maintained** and will only receive critical bug fixes. :warning:
![social](https://user-images.githubusercontent.com/325521/102897760-d1147b00-4468-11eb-9d7b-63a204bc9fc1.png)
This is an unofficial online tool to run Blood on the Clocktower games through Discord or other digital means.
@ -27,7 +29,7 @@ If you want to learn more about how to use the app as a player, [JayBotC](https:
### Custom Script Support
Any custom script generated by the official [Script Tool](https://bloodontheclocktower.com/script) is supported out of
Any custom script generated by the official [Script Tool](https://script.bloodontheclocktower.com/) is supported out of
the box and you only need to upload it to get the selected set of characters into your grimoire. If you want to customize
your script further, there is an additional `"_meta"` object that you can add to the script like you would add a normal
character:
@ -90,7 +92,8 @@ For base game characters, it is sufficient to only provide the ID, similar to wh
_Note_: custom images will only be visible after enabling them in the Grimoire menu!
- **edition**: the ID of the edition for this character. can be left blank or "custom"
- **firstNight** / **otherNight**: the position that this character acts on the first / other nights, compared to all
other characters
other characters<br>
_Note_: must be a positive number or zero, with zero being treated as "does not act during the night"
- **firstNightReminder** / **otherNightReminder**: reminder text for first / other nights
- **reminders**: reminder tokens, should be an empty array `[]` if none
- **remindersGlobal**: global reminder tokens that will always be available, no matter if the character is assigned to a player or not
@ -109,7 +112,7 @@ For base game characters, it is sufficient to only provide the ID, similar to wh
* [Blood on the Clocktower](https://bloodontheclocktower.com/) is a trademark of Steven Medway and [The Pandemonium Institute](https://www.thepandemoniuminstitute.com/)
* Night reminders and other auxiliary text written by [Ben Finney](http://bignose.whitetree.org/projects/botc/diy/)
* Iconography by [Font Awesome](https://fontawesome.com/)
* Background image by [Ryan Maloney](https://www.artstation.com/maloney94)
* Background image copyright and permission granted by [Ryan Maloney](https://www.artstation.com/maloney94)
* Webfonts by [Google Fonts](https://fonts.google.com/) and [Online Web Fonts](https://www.onlinewebfonts.com/)
* All other images and icons are copyright to their respective owners

22363
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "townsquare",
"version": "2.15.1",
"version": "2.16.2",
"description": "Blood on the Clocktower Town Square",
"author": "Steffen Baumgart",
"scripts": {
@ -15,22 +15,22 @@
"@fortawesome/free-brands-svg-icons": "^5.15.1",
"@fortawesome/free-solid-svg-icons": "^5.15.1",
"@fortawesome/vue-fontawesome": "^0.1.10",
"@vue/cli-service": "^4.5.9",
"@vue/cli-service": "^5.0.8",
"prom-client": "^13.0.0",
"sass": "^1.30.0",
"sass-loader": "^8.0.2",
"vue": "^2.6.12",
"vue-template-compiler": "^2.6.12",
"vue-template-compiler": "^2.7.15",
"vuex": "^3.6.0",
"ws": "^7.4.6"
},
"devDependencies": {
"@vue/cli-plugin-eslint": "^4.5.9",
"@vue/eslint-config-prettier": "^6.0.0",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.2.0",
"eslint-plugin-vue": "^6.2.2",
"prettier": "^1.19.1"
"@vue/cli-plugin-eslint": "^5.0.8",
"@vue/eslint-config-prettier": "^8.0.0",
"eslint": "^8.53.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-vue": "^9.18.1",
"prettier": "^3.0.3"
},
"keywords": [
"botc",

View File

@ -5,6 +5,8 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<title>Blood on the Clocktower Town Square</title>
<link rel="apple-touch-icon" sizes="57x57" href="static/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="static/apple-icon-60x60.png">

View File

@ -12,10 +12,14 @@ register.setDefaultLabels({
const PING_INTERVAL = 30000; // 30 seconds
const server = https.createServer({
cert: fs.readFileSync("cert.pem"),
key: fs.readFileSync("key.pem")
});
const options = {};
if (process.env.NODE_ENV !== "development") {
options.cert = fs.readFileSync("cert.pem");
options.key = fs.readFileSync("key.pem");
}
const server = https.createServer(options);
const wss = new WebSocket.Server({
...(process.env.NODE_ENV === "development" ? { port: 8081 } : { server }),
verifyClient: info =>
@ -234,7 +238,7 @@ const interval = setInterval(function ping() {
ws.readyState === WebSocket.CONNECTING)
)
) {
metrics.channels_list.remove([channel]);
metrics.channels_list.remove({ name: channel });
delete channels[channel];
}
}

BIN
src/assets/gstone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 142 KiB

BIN
src/assets/icons/damsel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 899 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
src/assets/icons/golem.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 856 KiB

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 838 KiB

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
src/assets/icons/noble.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

BIN
src/assets/icons/riot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

@ -1,20 +1,31 @@
<template>
<div class="intro">
<img src="static/apple-icon.png" alt="" />
Welcome to the (unofficial)
<b>Virtual Town Square and Grimoire</b> for Blood on the Clocktower! Please
add more players through the
<span class="button" @click="toggleMenu">
<font-awesome-icon icon="cog" /> Menu
</span>
on the top right or by pressing <b>[A]</b>. You can also join a game session
by pressing <b>[J]</b>.<br />
<div class="footer">
This project is free and open source and can be found on
<a href="https://github.com/bra1n/townsquare" target="_blank">GitHub</a>.
It is not affiliated with The Pandemonium Institute. "Blood on the
Clocktower" is a trademark of Steven Medway and The Pandemonium Institute.
<img src="static/apple-icon.png" alt="" class="logo" />
<div>
Welcome to the (unofficial)
<b>Virtual Town Square and Grimoire</b> for Blood on the Clocktower!
Please add more players through the
<span class="button" @click="toggleMenu">
<font-awesome-icon icon="cog" /> Menu
</span>
on the top right or by pressing <b>[A]</b>. You can also join a game
session by pressing <b>[J]</b>.<br />
<div class="footer">
This project is free and open source and can be found on
<a href="https://github.com/bra1n/townsquare" target="_blank">GitHub</a
>. It is not affiliated with The Pandemonium Institute. "Blood on the
Clocktower" is a trademark of Steven Medway and The Pandemonium
Institute.
</div>
</div>
<a
class="redirect"
v-if="language === 'zh-CN'"
href="https://clocktower.gstonegames.com"
>
<img src="../assets/gstone.png" class="gstone" alt="" />
你想使用中文版魔典吗
</a>
</div>
</template>
@ -22,6 +33,11 @@
import { mapMutations } from "vuex";
export default {
data() {
return {
language: window.navigator.userLanguage || window.navigator.language
};
},
methods: mapMutations(["toggleMenu"])
};
</script>
@ -38,15 +54,37 @@ export default {
border: 3px solid black;
border-radius: 10px;
z-index: 3;
display: flex;
justify-content: center;
a {
color: white;
}
img {
a.redirect {
display: block;
text-decoration: none;
position: absolute;
top: 100%;
margin-top: 2vh;
padding: 10px;
background: rgba(0, 0, 0, 0.5);
border: 3px solid black;
border-radius: 10px;
&:hover {
color: red;
}
img {
width: 120px;
display: block;
margin: auto;
margin-bottom: 1vh;
}
}
img.logo {
position: absolute;
bottom: 100%;
left: 50%;
width: 25vh;
margin-left: -12.5vh;
margin-bottom: 2vh;
max-width: 192px;
border-radius: 50%;

View File

@ -200,6 +200,7 @@
<div class="reminder add" @click="$emit('trigger', ['openReminderModal'])">
<span class="icon"></span>
</div>
<div class="reminderHoverTarget"></div>
</li>
</template>
@ -927,6 +928,19 @@ li.move:not(.from) .player .overlay svg.move {
opacity: 1;
}
}
.circle .reminderHoverTarget {
opacity: 0;
width: calc(50% + 8px);
padding-top: calc(50% + 38px);
margin-top: calc(-25% - 33px);
margin-left: calc(-25% - 1px);
border-radius: 0 0 999px 999px;
pointer-events: auto;
transform: none !important;
z-index: -1;
}
.circle li:hover .reminder.add {
opacity: 1;
top: 0;

View File

@ -19,10 +19,7 @@
class="leaf-right"
v-if="role.otherNight || role.otherNightReminder"
></span>
<span
v-if="role.reminders && role.reminders.length"
:class="['leaf-top' + role.reminders.length]"
></span>
<span v-if="reminderLeaves" :class="['leaf-top' + reminderLeaves]"></span>
<span class="leaf-orange" v-if="role.setup"></span>
<svg viewBox="0 0 150 150" class="name">
<path
@ -61,6 +58,12 @@ export default {
}
},
computed: {
reminderLeaves: function() {
return (
(this.role.reminders || []).length +
(this.role.remindersGlobal || []).length
);
},
...mapState(["grimoire"])
},
data() {

View File

@ -257,6 +257,7 @@ export default {
</script>
<style lang="scss">
@use "sass:math";
@import "../vars.scss";
#townsquare {
@ -301,14 +302,14 @@ export default {
}
@mixin on-circle($item-count) {
$angle: (360 / $item-count);
$angle: math.div(360, $item-count);
$rot: 0;
// rotation and tooltip placement
@for $i from 1 through $item-count {
&:nth-child(#{$i}) {
transform: rotate($rot * 1deg);
@if $i - 1 <= $item-count / 2 {
@if $i - 1 <= math.div($item-count, 2) {
// first half of players
z-index: $item-count - $i + 1;
// open menu on the left
@ -372,15 +373,15 @@ export default {
}
// move reminders closer to the sides of the circle
$q: $item-count / 4;
$q: math.div($item-count, 4);
$x: $i - 1;
@if $x < $q or ($x >= $item-count / 2 and $x < $q * 3) {
@if $x < $q or ($x >= math.div($item-count, 2) and $x < $q * 3) {
.player {
margin-bottom: -10% + 20% * (1 - ($x % $q / $q));
margin-bottom: -10% + 20% * (1 - math.div($x % $q, $q));
}
} @else {
.player {
margin-bottom: -10% + 20% * ($x % $q / $q);
margin-bottom: -10% + 20% * math.div($x % $q, $q);
}
}
}

View File

@ -32,7 +32,7 @@
<h3>Load custom script / characters</h3>
To play with a custom script, you need to select the characters you want
to play with in the official
<a href="https://bloodontheclocktower.com/script-tool/" target="_blank"
<a href="https://script.bloodontheclocktower.com/" target="_blank"
>Script Tool</a
>
and then upload the generated "custom-list.json" either directly here or
@ -69,6 +69,9 @@
<div class="button" @click="promptURL">
<font-awesome-icon icon="link" /> Enter URL
</div>
<div class="button" @click="readFromClipboard">
<font-awesome-icon icon="clipboard" /> Use JSON from Clipboard
</div>
<div class="button" @click="isCustom = false">
<font-awesome-icon icon="undo" /> Back
</div>
@ -156,8 +159,18 @@ export default {
}
}
},
async readFromClipboard() {
const text = await navigator.clipboard.readText();
try {
const roles = JSON.parse(text);
this.parseRoles(roles);
} catch (e) {
alert("Error reading custom script: " + e.message);
}
},
parseRoles(roles) {
if (!roles || !roles.length) return;
roles = roles.map(role => typeof role === "string" ? { id: role } : role);
const metaIndex = roles.findIndex(({ id }) => id === "_meta");
let meta = {};
if (metaIndex > -1) {
@ -169,11 +182,11 @@ export default {
Object.assign({}, meta, { id: "custom" })
);
// check for fabled and set those too, if present
if (roles.some(({ id }) => this.$store.state.fabled.has(id))) {
if (roles.some((role) => this.$store.state.fabled.has(role.id || role))) {
const fabled = [];
roles.forEach(({ id }) => {
if (this.$store.state.fabled.has(id)) {
fabled.push(this.$store.state.fabled.get(id));
roles.forEach((role) => {
if (this.$store.state.fabled.has(role.id || role)) {
fabled.push(this.$store.state.fabled.get(role.id || role));
}
});
this.$store.commit("players/setFabled", { fabled });

View File

@ -40,7 +40,9 @@ export default {
roles: this.edition.isOfficial
? ""
: this.$store.getters.customRolesStripped,
fabled: this.players.fabled.map(({ id }) => id),
fabled: this.players.fabled.map(fabled =>
fabled.isCustom ? fabled : { id: fabled.id }
),
players: this.players.players.map(player => ({
...player,
role: player.role.id || {}
@ -79,7 +81,12 @@ export default {
}
if (fabled) {
this.$store.commit("players/setFabled", {
fabled: fabled.map(id => this.$store.state.fabled.get(id))
fabled: fabled.map(
f =>
this.$store.state.fabled.get(f) ||
this.$store.state.fabled.get(f.id) ||
f
)
});
}
if (players) {

View File

@ -115,7 +115,7 @@ export default {
{
id: "evil",
name: "Minion info",
firstNight: 4,
firstNight: 5,
team: "minion",
players: this.players.filter(p => p.role.team === "minion"),
firstNightReminder:
@ -125,7 +125,7 @@ export default {
{
id: "evil",
name: "Demon info & bluffs",
firstNight: 7,
firstNight: 8,
team: "demon",
players: this.players.filter(p => p.role.team === "demon"),
firstNightReminder:

View File

@ -100,6 +100,7 @@ export default {
value: role
});
}
this.tab = "editionRoles";
this.$store.commit("toggleModal", "role");
},
close() {

View File

@ -113,14 +113,14 @@
},
{
"id": "djinn",
"firstNight": 1,
"firstNightReminder": "Wake each evil player and show them which jinxed characters are in play, so that they know not to bluff as characters that can not be in play.",
"firstNight": 0,
"firstNightReminder": "",
"otherNightReminder": "",
"reminders": [],
"setup": false,
"name": "Djinn",
"team": "fabled",
"ability": "Jinxed characters are not both in-play, but evil players know which ones are. Or, use the Djinn's \"Special Rule\"."
"ability": "Use the Djinn's special rule. All players know what it is."
},
{
"id": "stormcatcher",
@ -132,15 +132,5 @@
"name": "Storm Catcher",
"team": "fabled",
"ability": "Name a good character. If in play, they can only die by execution, but evil players learn which player it is."
},
{
"id": "deusexfiasco",
"firstNightReminder": "",
"otherNightReminder": "",
"reminders": ["Whoops"],
"setup": false,
"name": "Deus ex Fiasco",
"team": "fabled",
"ability": "Once per game, the Storyteller will make a \"mistake\", correct it and publicly admit to it."
}
]

View File

@ -1,178 +1,361 @@
[{
"id": "Chambermaid",
"hatred": [{
"id": "Mathematician",
"reason": "The Chambermaid learns if the Mathematician wakes tonight or not, even though the Chambermaid wakes first."
}]
},
{
"id": "Butler",
"hatred": [{
"id": "Cannibal",
"reason": "If the Cannibal gains the Butler ability, the Cannibal learns this."
}]
},
{
"id": "Mutant",
"hatred": [{
"id": "Undertaker",
"reason": "If the Mutant causes a second execution, the Undertaker learns either one or both executed characters (Storyteller's choice)."
}]
},
{
"id": "Lunatic",
"hatred": [{
"id": "Mathematician",
"reason": "The Mathematician learns if the Lunatic attacks a different player(s) than the real Demon attacked."
}]
},
{
"id": "Pit-Hag",
"hatred": [{
"id": "Politician",
"reason": "A Pit-Hag can not create an evil Politician."
},
{
"id": "Heretic",
"reason": "A Pit-Hag can not create a Heretic. "
}
]
},
{
"id": "Cerenovus",
"hatred": [{
"id": "Undertaker",
"reason": "If the Cerenovus causes a second execution, the Undertaker learns either one or both executed characters (Storyteller's choice)."
},
{
"id": "Goblin",
"reason": "The Cerenovus may choose to make a player mad that they are the Goblin."
}
]
},
{
"id": "Leviathan",
"hatred": [{
"id": "Soldier",
"reason": "If Leviathan nominates and executes the Soldier, the Soldier does not die."
},
{
"id": "Monk",
"reason": "If Leviathan nominates and executes the player the Monk chose, that player does not die."
},
{
"id": "Innkeeper",
"reason": "If Leviathan nominates and executes a player the Innkeeper chose, that player does not die."
},
{
"id": "Ravenkeeper",
"reason": "If Leviathan is in play & the Ravenkeeper dies by execution, they wake that night to use their ability."
},
{
"id": "Sage",
"reason": "If Leviathan is in play & the Sage dies by execution, they wake that night to use their ability."
},
{
"id": "Mayor",
"reason": "If Leviathan is in play & no execution occurs on day 5, good wins."
},
{
"id": "Farmer",
"reason": "If Leviathan is in play & a Farmer dies by execution, a good player becomes a Farmer that night."
}
]
},
{
"id": "Lil' Monsta",
"hatred": [{
"id": "Scarlet Woman",
"reason": "If there are 5 or more players alive and the player holding the Lil' Monsta token dies, the Scarlet Woman is given the Lil' Monsta token tonight."
},
{
"id": "Poppy Grower",
"reason": "If the Poppy Grower is in play, Minions don't wake together. They are woken one by one, until one of them chooses to take the Lil' Monsta token."
},
{
"id": "Magician",
"reason": "Only 1 jinxed character can be in play. "
}
]
},
{
"id": "Lycanthrope",
"hatred": [{
"id": "Gambler",
"reason": "If the Lycanthrope is alive and the Gambler kills themself at night, no other players can die tonight."
}]
},
{
"id": "Legion",
"hatred": [{
"id": "Preacher",
"reason": "Only 1 jinxed character can be in play. Evil players start knowing which player and character it is."
}]
},
{
"id": "Fang Gu",
"hatred": [{
"id": "Scarlet Woman",
"reason": "If the Fang Gu chooses an Outsider and dies, the Scarlet Woman does not become the Fang Gu."
}]
},
{
"id": "Spy",
"hatred": [{
"id": "Poppy Grower",
"reason": "If the Poppy Grower is in play, the Spy does not see the Grimoire until the Poppy Grower dies."
},
{
"id": "Heretic",
"reason": "Only 1 jinxed character can be in play."
},
{
"id": "Magician",
"reason": "When the Spy sees the Grimoire, the Demon and Magician's character tokens are removed."
}
]
},
{
"id": "Widow",
"hatred": [{
"id": "Poppy Grower",
"reason": "If the Poppy Grower is in play, the Widow does not see the Grimoire until the Poppy Grower dies."
},
{
"id": "Heretic",
"reason": "Only 1 jinxed character can be in play."
},
{
"id": "Magician",
"reason": "When the Widow sees the Grimoire, the Demon and Magician's character tokens are removed."
}
]
}, {
"id": "Godfather",
"hatred": [{
"id": "Heretic",
"reason": "Only 1 jinxed character can be in play."
}]
}, {
"id": "Marionette",
"hatred": [{
"id": "Lil' Monsta",
"reason": "The Marionette neighbors a Minion, not the Demon. The Marionette is not woken to choose who takes the Lil' Monsta token."
},
{
"id": "Poppy Grower",
"reason": "When the Poppy Grower dies, the Demon learns the Marionette but the Marionette learns nothing."
},
{
"id": "Balloonist",
"reason": "If the Marionette thinks that they are the Balloonist, +1 Outsider was added."
}
]
},
[
{
"id": "Chambermaid",
"hatred": [
{
"id": "Mathematician",
"reason": "The Chambermaid learns if the Mathematician wakes tonight or not, even though the Chambermaid wakes first."
}
]
},
{
"id": "Butler",
"hatred": [
{
"id": "Cannibal",
"reason": "If the Cannibal gains the Butler ability, the Cannibal learns this."
}
]
},
{
"id": "Lunatic",
"hatred": [
{
"id": "Mathematician",
"reason": "The Mathematician learns if the Lunatic attacks a different player(s) than the real Demon attacked."
}
]
},
{
"id": "Pit-Hag",
"hatred": [
{
"id": "Heretic",
"reason": "A Pit-Hag can not create a Heretic. "
},
{
"id": "Damsel",
"reason": "If a Pit-Hag creates a Damsel, the Storyteller chooses which player it is."
},
{
"id": "Politician",
"reason": "A Pit-hag can not create an evil Politician."
}
]
},
{
"id": "Cerenovus",
"hatred": [
{
"id": "Goblin",
"reason": "The Cerenovus may choose to make a player mad that they are the Goblin."
}
]
},
{
"id": "Leviathan",
"hatred": [
{
"id": "Soldier",
"reason": "If Leviathan nominates and executes the Soldier, the Soldier does not die."
},
{
"id": "Monk",
"reason": "If Leviathan nominates and executes the player the Monk chose, that player does not die."
},
{
"id": "Innkeeper",
"reason": "If Leviathan nominates and executes a player the Innkeeper chose, that player does not die."
},
{
"id": "Ravenkeeper",
"reason": "If Leviathan is in play & the Ravenkeeper dies by execution, they wake that night to use their ability."
},
{
"id": "Sage",
"reason": "If Leviathan is in play & the Sage dies by execution, they wake that night to use their ability."
},
{
"id": "Farmer",
"reason": "If Leviathan is in play & a Farmer dies by execution, a good player becomes a Farmer that night."
},
{
"id": "Mayor",
"reason": "If Leviathan is in play & no execution occurs on day 5, good wins."
}
]
},
{
"id": "Al-Hadikhia",
"hatred": [
{
"id": "Scarlet Woman",
"reason": "If there are two living Al-Hadikhias, the Scarlet Woman Al-Hadikhia becomes the Scarlet Woman again."
},
{
"id": "Mastermind",
"reason": "Only 1 jinxed character can be in play. Evil players start knowing which player and character it is."
}
]
},
{
"id": "Lil' Monsta",
"hatred": [
{
"id": "Poppy Grower",
"reason": "If the Poppy Grower is in play, Minions don't wake together. They are woken one by one, until one of them chooses to take the Lil' Monsta token."
},
{
"id": "Magician",
"reason": "Only 1 jinxed character can be in play. "
},
{
"id": "Scarlet Woman",
"reason": "If there are 5 or more players alive and the player holding the Lil' Monsta token dies, the Scarlet Woman is given the Lil' Monsta token tonight."
}
]
},
{
"id": "Lycanthrope",
"hatred": [
{
"id": "Gambler",
"reason": "If the Lycanthrope is alive and the Gambler kills themself at night, no other players can die tonight."
}
]
},
{
"id": "Legion",
"hatred": [
{
"id": "Engineer",
"reason": "Legion and the Engineer can not both be in play at the start of the game. If the Engineer creates Legion, most players (including all evil players) become evil Legion."
},
{
"id": "Preacher",
"reason": "Only 1 jinxed character can be in play."
}
]
},
{
"id": "Fang Gu",
"hatred": [
{
"id": "Scarlet Woman",
"reason": "If the Fang Gu chooses an Outsider and dies, the Scarlet Woman does not become the Fang Gu."
}
]
},
{
"id": "Spy",
"hatred": [
{
"id": "Magician",
"reason": "When the Spy sees the Grimoire, the Demon and Magician's character tokens are removed."
},
{
"id": "Alchemist",
"reason": "The Alchemist can not have the Spy ability."
},
{
"id": "Poppy Grower",
"reason": "If the Poppy Grower is in play, the Spy does not see the Grimoire until the Poppy Grower dies."
},
{
"id": "Damsel",
"reason": "Only 1 jinxed character can be in play. "
},
{
"id": "Heretic",
"reason": "Only 1 jinxed character can be in play."
}
]
},
{
"id": "Widow",
"hatred": [
{
"id": "Magician",
"reason": "When the Widow sees the Grimoire, the Demon and Magician's character tokens are removed."
},
{
"id": "Poppy Grower",
"reason": "If the Poppy Grower is in play, the Widow does not see the Grimoire until the Poppy Grower dies."
},
{
"id": "Alchemist",
"reason": "The Alchemist can not have the Widow ability."
},
{
"id": "Damsel",
"reason": "Only 1 jinxed character can be in play."
},
{
"id": "Heretic",
"reason": "Only 1 jinxed character can be in play."
}
]
},
{
"id": "Godfather",
"hatred": [
{
"id": "Heretic",
"reason": "Only 1 jinxed character can be in play."
}
]
},
{
"id": "Baron",
"hatred": [
{
"id": "Heretic",
"reason": "The Baron might only add 1 Outsider, not 2."
}
]
},
{
"id": "Marionette",
"hatred": [
{
"id": "Lil' Monsta",
"reason": "The Marionette neighbors a Minion, not the Demon. The Marionette is not woken to choose who takes the Lil' Monsta token."
},
{
"id": "Poppy Grower",
"reason": "When the Poppy Grower dies, the Demon learns the Marionette but the Marionette learns nothing."
},
{
"id": "Snitch",
"reason": "The Marionette does not learn 3 not in-play characters. The Demon learns an extra 3 instead."
},
{
"id": "Balloonist",
"reason": "If the Marionette thinks that they are the Balloonist, +1 Outsider was added."
},
{
"id": "Damsel",
"reason": "The Marionette does not learn that a Damsel is in play."
},
{
"id": "Huntsman",
"reason": "If the Marionette thinks that they are the Huntsman, the Damsel was added."
}
]
},
{
"id": "Riot",
"hatred": [
{
"id": "Engineer",
"reason": "Riot and the Engineer can not both be in play at the start of the game. \nIf the Engineer creates Riot, the evil players become Riot."
},
{
"id": "Golem",
"reason": "If The Golem nominates Riot, the Riot player does not die."
},
{
"id": "Snitch",
"reason": "If the Snitch is in play, each Riot player gets an extra 3 bluffs."
},
{
"id": "Saint",
"reason": "If a good player nominates and kills the Saint, the Saint's team loses."
},
{
"id": "Butler",
"reason": "The Butler can not nominate their master."
},
{
"id": "Pit-Hag",
"reason": "If the Pit-Hag creates Riot, all evil players become Riot. \nIf the Pit-Hag creates Riot after day 3, the game continues for one more day."
},
{
"id": "Mayor",
"reason": "If the 3rd day begins with just three players alive, the players may choose (as a group) not to nominate at all. If so (and a Mayor is alive) then the Mayor's team wins."
},
{
"id": "Monk",
"reason": "If a Riot player nominates and kills the Monk-protected-player, the Monk-protected-player does not die."
},
{
"id": "Farmer",
"reason": "If a Riot player nominates and kills a Farmer, the Farmer uses their ability tonight."
},
{
"id": "Innkeeper",
"reason": "If a Riot player nominates an Innkeeper-protected-player, the Innkeeper-protected-player does not die."
},
{
"id": "Sage",
"reason": "If a Riot player nominates and kills a Sage, the Sage uses their ability tonight."
},
{
"id": "Ravenkeeper",
"reason": "If a Riot player nominates and kills the Ravenkeeper, the Ravenkeeper uses their ability tonight."
},
{
"id": "Soldier",
"reason": "If a Riot player nominates the Soldier, the Soldier does not die."
},
{
"id": "Grandmother",
"reason": "If a Riot player nominates and kills the Grandchild, the Grandmother dies too."
},
{
"id": "King",
"reason": "If a Riot player nominates and kills the King and the Choirboy is alive, the Choirboy uses their ability tonight."
},
{
"id": "Exorcist",
"reason": "Only 1 jinxed character can be in play."
},
{
"id": "Minstrel",
"reason": "Only 1 jinxed character can be in play."
},
{
"id": "Flowergirl",
"reason": "Only 1 jinxed character can be in play."
},
{
"id": "Undertaker",
"reason": "Players that die by nomination register as being executed to the Undertaker."
},
{
"id": "Cannibal",
"reason": "Players that die by nomination register as being executed to the Cannibal."
},
{
"id": "Pacifist",
"reason": "Players that die by nomination register as being executed to the Pacifist."
},
{
"id": "Devil's Advocate",
"reason": "Players that die by nomination register as being executed to the Devil's Advocate."
},
{
"id": "Investigator",
"reason": "Riot registers as a Minion to the Investigator."
},
{
"id": "Clockmaker",
"reason": "Riot registers as a Minion to the Clockmaker."
},
{
"id": "Town Crier",
"reason": "Riot registers as a Minion to the Town Crier."
},
{
"id": "Damsel",
"reason": "Riot registers as a Minion to the Damsel."
},
{
"id": "Preacher",
"reason": "Riot registers as a Minion to the Preacher."
}
]
},
{
"id": "Lleech",
"hatred": [
@ -183,7 +366,11 @@
{
"id": "Slayer",
"reason": "If the Slayer slays the Lleech's host, the host dies. "
},
{
"id": "Heretic",
"reason": "If the Lleech has poisoned the Heretic then the Lleech dies, the Heretic remains poisoned."
}
]
}
]
]

View File

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

View File

@ -4,7 +4,7 @@
"name": "Washerwoman",
"edition": "tb",
"team": "townsfolk",
"firstNight": 27,
"firstNight": 33,
"firstNightReminder": "Show the character token of a Townsfolk in play. Point to two players, one of which is that character.",
"otherNight": 0,
"otherNightReminder": "",
@ -18,7 +18,7 @@
"name": "Librarian",
"edition": "tb",
"team": "townsfolk",
"firstNight": 28,
"firstNight": 34,
"firstNightReminder": "Show the character token of an Outsider in play. Point to two players, one of which is that character.",
"otherNight": 0,
"otherNightReminder": "",
@ -32,7 +32,7 @@
"name": "Investigator",
"edition": "tb",
"team": "townsfolk",
"firstNight": 29,
"firstNight": 35,
"firstNightReminder": "Show the character token of a Minion in play. Point to two players, one of which is that character.",
"otherNight": 0,
"otherNightReminder": "",
@ -46,7 +46,7 @@
"name": "Chef",
"edition": "tb",
"team": "townsfolk",
"firstNight": 30,
"firstNight": 36,
"firstNightReminder": "Show the finger signal (0, 1, 2, \u2026) for the number of pairs of neighbouring evil players.",
"otherNight": 0,
"otherNightReminder": "",
@ -59,9 +59,9 @@
"name": "Empath",
"edition": "tb",
"team": "townsfolk",
"firstNight": 31,
"firstNight": 37,
"firstNightReminder": "Show the finger signal (0, 1, 2) for the number of evil alive neighbours of the Empath.",
"otherNight": 48,
"otherNight": 53,
"otherNightReminder": "Show the finger signal (0, 1, 2) for the number of evil neighbours.",
"reminders": [],
"setup": false,
@ -72,9 +72,9 @@
"name": "Fortune Teller",
"edition": "tb",
"team": "townsfolk",
"firstNight": 32,
"firstNight": 38,
"firstNightReminder": "The Fortune Teller points to two players. Give the head signal (nod yes, shake no) for whether one of those players is the Demon. ",
"otherNight": 49,
"otherNight": 54,
"otherNightReminder": "The Fortune Teller points to two players. Show the head signal (nod 'yes', shake 'no') for whether one of those players is the Demon.",
"reminders": ["Red herring"],
"setup": false,
@ -87,7 +87,7 @@
"team": "townsfolk",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 51,
"otherNight": 55,
"otherNightReminder": "If a player was executed today: Show that player\u2019s character token.",
"reminders": ["Executed"],
"setup": false,
@ -113,7 +113,7 @@
"team": "townsfolk",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 39,
"otherNight": 52,
"otherNightReminder": "If the Ravenkeeper died tonight: The Ravenkeeper points to a player. Show that player\u2019s character token.",
"reminders": [],
"setup": false,
@ -176,9 +176,9 @@
"name": "Butler",
"edition": "tb",
"team": "outsider",
"firstNight": 33,
"firstNight": 39,
"firstNightReminder": "The Butler points to a player. Mark that player as 'Master'.",
"otherNight": 50,
"otherNight": 67,
"otherNightReminder": "The Butler points to a player. Mark that player as 'Master'.",
"reminders": ["Master"],
"setup": false,
@ -229,7 +229,7 @@
"name": "Poisoner",
"edition": "tb",
"team": "minion",
"firstNight": 15,
"firstNight": 17,
"firstNightReminder": "The Poisoner points to a player. That player is poisoned.",
"otherNight": 7,
"otherNightReminder": "The previously poisoned player is no longer poisoned. The Poisoner points to a player. That player is poisoned.",
@ -242,9 +242,9 @@
"name": "Spy",
"edition": "tb",
"team": "minion",
"firstNight": 41,
"firstNight": 49,
"firstNightReminder": "Show the Grimoire to the Spy for as long as they need.",
"otherNight": 62,
"otherNight": 68,
"otherNightReminder": "Show the Grimoire to the Spy for as long as they need.",
"reminders": [],
"setup": false,
@ -257,7 +257,7 @@
"team": "minion",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 18,
"otherNight": 19,
"otherNightReminder": "If the Scarlet Woman became the Demon today: Show the 'You are' card, then the demon token.",
"reminders": ["Demon"],
"setup": false,
@ -283,7 +283,7 @@
"team": "demon",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 22,
"otherNight": 24,
"otherNightReminder": "The Imp points to a player. That player dies. If the Imp chose themselves: Replace the character of 1 alive minion with a spare Imp token. Show the 'You are' card, then the Imp token.",
"reminders": ["Dead"],
"setup": false,
@ -352,16 +352,16 @@
"otherNightReminder": "",
"reminders": [],
"setup": false,
"ability": "You must use a vote token to vote. Dead players may choose to give you theirs. If so, you learn their alignment."
"ability": "You must use a vote token to vote. Dead players may choose to give you theirs. If so, you learn their alignment. You are sober & healthy."
},
{
"id": "grandmother",
"name": "Grandmother",
"edition": "bmr",
"team": "townsfolk",
"firstNight": 34,
"firstNight": 40,
"firstNightReminder": "Show the marked character token. Point to the marked player.",
"otherNight": 47,
"otherNight": 51,
"otherNightReminder": "If the Grandmother\u2019s grandchild was killed by the Demon tonight: The Grandmother dies.",
"reminders": ["Grandchild"],
"setup": false,
@ -372,7 +372,7 @@
"name": "Sailor",
"edition": "bmr",
"team": "townsfolk",
"firstNight": 9,
"firstNight": 11,
"firstNightReminder": "The Sailor points to a living player. Either the Sailor, or the chosen player, is drunk.",
"otherNight": 4,
"otherNightReminder": "The previously drunk player is no longer drunk. The Sailor points to a living player. Either the Sailor, or the chosen player, is drunk.",
@ -385,9 +385,9 @@
"name": "Chambermaid",
"edition": "bmr",
"team": "townsfolk",
"firstNight": 44,
"firstNight": 51,
"firstNightReminder": "The Chambermaid points to two players. Show the number signal (0, 1, 2, \u2026) for how many of those players wake tonight for their ability.",
"otherNight": 65,
"otherNight": 70,
"otherNightReminder": "The Chambermaid points to two players. Show the number signal (0, 1, 2, \u2026) for how many of those players wake tonight for their ability.",
"reminders": [],
"setup": false,
@ -400,7 +400,7 @@
"team": "townsfolk",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 20,
"otherNight": 21,
"otherNightReminder": "The Exorcist points to a player, different from the previous night. If that player is the Demon: Wake the Demon. Show the Exorcist token. Point to the Exorcist. The Demon does not act tonight.",
"reminders": ["Chosen"],
"setup": false,
@ -413,7 +413,7 @@
"team": "townsfolk",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 8,
"otherNight": 9,
"otherNightReminder": "The previously protected and drunk players lose those markers. The Innkeeper points to two players. Those players are protected. One is drunk.",
"reminders": ["Protected",
"Drunk"],
@ -440,7 +440,7 @@
"team": "townsfolk",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 44,
"otherNight": 38,
"otherNightReminder": "If the Gossip\u2019s public statement was true: Choose a player not protected from dying tonight. That player dies.",
"reminders": ["Dead"],
"setup": false,
@ -451,9 +451,9 @@
"name": "Courtier",
"edition": "bmr",
"team": "townsfolk",
"firstNight": 17,
"firstNight": 19,
"firstNightReminder": "The Courtier either shows a 'no' head signal, or points to a character on the sheet. If the Courtier used their ability: If that character is in play, that player is drunk.",
"otherNight": 9,
"otherNight": 8,
"otherNightReminder": "Reduce the remaining number of days the marked player is poisoned. If the Courtier has not yet used their ability: The Courtier either shows a 'no' head signal, or points to a character on the sheet. If the Courtier used their ability: If that character is in play, that player is drunk.",
"reminders": ["Drunk 3",
"Drunk 2",
@ -469,7 +469,7 @@
"team": "townsfolk",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 42,
"otherNight": 43,
"otherNightReminder": "If the Professor has not used their ability: The Professor either shakes their head no, or points to a player. If that player is a Townsfolk, they are now alive.",
"reminders": ["Alive",
"No ability"],
@ -535,7 +535,7 @@
"team": "outsider",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 45,
"otherNight": 49,
"otherNightReminder": "The Tinker might die.",
"reminders": ["Dead"],
"setup": false,
@ -548,7 +548,7 @@
"team": "outsider",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 46,
"otherNight": 50,
"otherNightReminder": "If the Moonchild used their ability to target a player today: If that player is good, they die.",
"reminders": ["Dead"],
"setup": false,
@ -572,9 +572,9 @@
"name": "Lunatic",
"edition": "bmr",
"team": "outsider",
"firstNight": 6,
"firstNight": 8,
"firstNightReminder": "If 7 or more players: Show the Lunatic a number of arbitrary 'Minions', players equal to the number of Minions in play. Show 3 character tokens of arbitrary good characters. If the token received by the Lunatic is a Demon that would wake tonight: Allow the Lunatic to do the Demon actions. Place their 'attack' markers. Wake the Demon. Show the Demon\u2019s real character token. Show them the Lunatic player. If the Lunatic attacked players: Show the real demon each marked player. Remove any Lunatic 'attack' markers.",
"otherNight": 19,
"otherNight": 20,
"otherNightReminder": "Allow the Lunatic to do the actions of the Demon. Place their 'attack' markers. If the Lunatic selected players: Wake the Demon. Show the 'attack' marker, then point to each marked player. Remove any Lunatic 'attack' markers.",
"reminders": ["Attack 1",
"Attack 2",
@ -587,9 +587,9 @@
"name": "Godfather",
"edition": "bmr",
"team": "minion",
"firstNight": 19,
"firstNight": 21,
"firstNightReminder": "Show each of the Outsider tokens in play.",
"otherNight": 35,
"otherNight": 37,
"otherNightReminder": "If an Outsider died today: The Godfather points to a player. That player dies.",
"reminders": ["Died today",
"Dead"],
@ -601,7 +601,7 @@
"name": "Devil's Advocate",
"edition": "bmr",
"team": "minion",
"firstNight": 20,
"firstNight": 22,
"firstNightReminder": "The Devil\u2019s Advocate points to a living player. That player survives execution tomorrow.",
"otherNight": 13,
"otherNightReminder": "The Devil\u2019s Advocate points to a living player, different from the previous night. That player survives execution tomorrow.",
@ -616,7 +616,7 @@
"team": "minion",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 34,
"otherNight": 36,
"otherNightReminder": "If the Assassin has not yet used their ability: The Assassin either shows the 'no' head signal, or points to a player. That player dies.",
"reminders": ["Dead",
"No ability"],
@ -643,7 +643,7 @@
"team": "demon",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 23,
"otherNight": 25,
"otherNightReminder": "If no-one died during the day: The Zombuul points to a player. That player dies.",
"reminders": ["Died today",
"Dead"],
@ -655,9 +655,9 @@
"name": "Pukka",
"edition": "bmr",
"team": "demon",
"firstNight": 25,
"firstNight": 28,
"firstNightReminder": "The Pukka points to a player. That player is poisoned.",
"otherNight": 24,
"otherNight": 26,
"otherNightReminder": "The Pukka points to a player. That player is poisoned. The previously poisoned player dies. ",
"reminders": ["Poisoned",
"Dead"],
@ -671,7 +671,7 @@
"team": "demon",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 25,
"otherNight": 27,
"otherNightReminder": "One player that the Shabaloth chose the previous night might be resurrected. The Shabaloth points to two players. Those players die.",
"reminders": ["Dead",
"Alive"],
@ -685,7 +685,7 @@
"team": "demon",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 26,
"otherNight": 28,
"otherNightReminder": "If the Po chose no-one the previous night: The Po points to three players. Otherwise: The Po either shows the 'no' head signal , or points to a player. Chosen players die",
"reminders": ["Dead",
"3 attacks"],
@ -763,7 +763,7 @@
"name": "Clockmaker",
"edition": "snv",
"team": "townsfolk",
"firstNight": 35,
"firstNight": 41,
"firstNightReminder": "Show the hand signal for the number (1, 2, 3, etc.) of places from Demon to closest Minion.",
"otherNight": 0,
"otherNightReminder": "",
@ -776,9 +776,9 @@
"name": "Dreamer",
"edition": "snv",
"team": "townsfolk",
"firstNight": 36,
"firstNight": 42,
"firstNightReminder": "The Dreamer points to a player. Show 1 good and 1 evil character token; one of these is correct.",
"otherNight": 52,
"otherNight": 56,
"otherNightReminder": "The Dreamer points to a player. Show 1 good and 1 evil character token; one of these is correct.",
"reminders": [],
"setup": false,
@ -789,7 +789,7 @@
"name": "Snake Charmer",
"edition": "snv",
"team": "townsfolk",
"firstNight": 18,
"firstNight": 20,
"firstNightReminder": "The Snake Charmer points to a player. If that player is the Demon: swap the Demon and Snake Charmer character and alignments. Wake each player to inform them of their new role and alignment. The new Snake Charmer is poisoned.",
"otherNight": 11,
"otherNightReminder": "The Snake Charmer points to a player. If that player is the Demon: swap the Demon and Snake Charmer character and alignments. Wake each player to inform them of their new role and alignment. The new Snake Charmer is poisoned.",
@ -802,9 +802,9 @@
"name": "Mathematician",
"edition": "snv",
"team": "townsfolk",
"firstNight": 43,
"firstNight": 52,
"firstNightReminder": "Show the hand signal for the number (0, 1, 2, etc.) of players whose ability malfunctioned due to other abilities.",
"otherNight": 64,
"otherNight": 71,
"otherNightReminder": "Show the hand signal for the number (0, 1, 2, etc.) of players whose ability malfunctioned due to other abilities.",
"reminders": ["Abnormal"],
"setup": false,
@ -817,7 +817,7 @@
"team": "townsfolk",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 53,
"otherNight": 57,
"otherNightReminder": "Nod 'yes' or shake head 'no' for whether the Demon voted today. Place the 'Demon not voted' marker (remove 'Demon voted', if any).",
"reminders": ["Demon voted",
"Demon not voted"],
@ -831,12 +831,12 @@
"team": "townsfolk",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 54,
"otherNight": 58,
"otherNightReminder": "Nod 'yes' or shake head 'no' for whether a Minion nominated today. Place the 'Minion not nominated' marker (remove 'Minion nominated', if any).",
"reminders": ["Minions not nominated",
"Minion nominated"],
"setup": false,
"ability": "Each night*, you learn if a Minion nominated today"
"ability": "Each night*, you learn if a Minion nominated today."
},
{
"id": "oracle",
@ -845,7 +845,7 @@
"team": "townsfolk",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 55,
"otherNight": 59,
"otherNightReminder": "Show the hand signal for the number (0, 1, 2, etc.) of dead evil players.",
"reminders": [],
"setup": false,
@ -869,9 +869,9 @@
"name": "Seamstress",
"edition": "snv",
"team": "townsfolk",
"firstNight": 37,
"firstNight": 43,
"firstNightReminder": "The Seamstress either shows a 'no' head signal, or points to two other players. If the Seamstress chose players , nod 'yes' or shake 'no' for whether they are of same alignment.",
"otherNight": 56,
"otherNight": 60,
"otherNightReminder": "If the Seamstress has not yet used their ability: the Seamstress either shows a 'no' head signal, or points to two other players. If the Seamstress chose players , nod 'yes' or shake 'no' for whether they are of same alignment.",
"reminders": ["No ability"],
"setup": false,
@ -883,9 +883,9 @@
"edition": "snv",
"team": "townsfolk",
"firstNight": 2,
"firstNightReminder": "The Philosopher either shows a 'no' head signal, or points to a good character on their sheet. If they chose a character: Swap the out-of-play character token with the Philosopher token. Or, if the character is in play, place the drunk marker by that player and the Not the Philosopher token by the Philosopher.",
"firstNightReminder": "The Philosopher either shows a 'no' head signal, or points to a good character on their sheet. If they chose a character: Swap the out-of-play character token with the Philosopher token and add the 'Is the Philosopher' reminder. If the character is in play, place the drunk marker by that player.",
"otherNight": 2,
"otherNightReminder": "If the Philosopher has not used their ability: the Philosopher either shows a 'no' head signal, or points to a good character on their sheet. If they chose a character: Swap the out-of-play character token with the Philosopher token. Or, if the character is in play, place the drunk marker by that player and the Not the Philosopher token by the Philosopher.",
"otherNightReminder": "If the Philosopher has not used their ability: the Philosopher either shows a 'no' head signal, or points to a good character on their sheet. If they chose a character: Swap the out-of-play character token with the Philosopher token and add the 'Is the Philosopher' reminder. If the character is in play, place the drunk marker by that player.",
"reminders": ["Drunk",
"Is the Philosopher"],
"setup": false,
@ -911,7 +911,7 @@
"team": "townsfolk",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 57,
"otherNight": 61,
"otherNightReminder": "If today was the Juggler\u2019s first day: Show the hand signal for the number (0, 1, 2, etc.) of 'Correct' markers. Remove markers.",
"reminders": ["Correct"],
"setup": false,
@ -924,7 +924,7 @@
"team": "townsfolk",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 40,
"otherNight": 42,
"otherNightReminder": "If the Sage was killed by a Demon: Point to two players, one of which is that Demon.",
"reminders": [],
"setup": false,
@ -950,7 +950,7 @@
"team": "outsider",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 38,
"otherNight": 41,
"otherNightReminder": "Choose a player that is drunk.",
"reminders": ["Drunk"],
"setup": false,
@ -963,7 +963,7 @@
"team": "outsider",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 37,
"otherNight": 40,
"otherNightReminder": "If the Barber died today: Wake the Demon. Show the 'This character selected you' card, then Barber token. The Demon either shows a 'no' head signal, or points to 2 players. If they chose players: Swap the character tokens. Wake each player. Show 'You are', then their new character token.",
"reminders": ["Haircuts tonight"],
"setup": false,
@ -987,7 +987,7 @@
"name": "Evil Twin",
"edition": "snv",
"team": "minion",
"firstNight": 21,
"firstNight": 23,
"firstNightReminder": "Wake the Evil Twin and their twin. Confirm that they have acknowledged each other. Point to the Evil Twin. Show their Evil Twin token to the twin player. Point to the twin. Show their character token to the Evil Twin player.",
"otherNight": 0,
"otherNightReminder": "",
@ -1000,7 +1000,7 @@
"name": "Witch",
"edition": "snv",
"team": "minion",
"firstNight": 22,
"firstNight": 24,
"firstNightReminder": "The Witch points to a player. If that player nominates tomorrow they die immediately.",
"otherNight": 14,
"otherNightReminder": "If there are 4 or more players alive: The Witch points to a player. If that player nominates tomorrow they die immediately.",
@ -1013,7 +1013,7 @@
"name": "Cerenovus",
"edition": "snv",
"team": "minion",
"firstNight": 23,
"firstNight": 25,
"firstNightReminder": "The Cerenovus points to a player, then to a character on their sheet. Wake that player. Show the 'This character selected you' card, then the Cerenovus token. Show the selected character token. If the player is not mad about being that character tomorrow, they can be executed.",
"otherNight": 15,
"otherNightReminder": "The Cerenovus points to a player, then to a character on their sheet. Wake that player. Show the 'This character selected you' card, then the Cerenovus token. Show the selected character token. If the player is not mad about being that character tomorrow, they can be executed.",
@ -1041,9 +1041,10 @@
"team": "demon",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 27,
"otherNight": 29,
"otherNightReminder": "The Fang Gu points to a player. That player dies. Or, if that player was an Outsider and there are no other Fang Gu in play: The Fang Gu dies instead of the chosen player. The chosen player is now an evil Fang Gu. Wake the new Fang Gu. Show the 'You are' card, then the Fang Gu token. Show the 'You are' card, then the thumb-down 'evil' hand sign.",
"reminders": ["Dead"],
"reminders": ["Dead",
"Once"],
"setup": true,
"ability": "Each night*, choose a player: they die. The 1st Outsider this kills becomes an evil Fang Gu & you die instead. [+1 Outsider]"
},
@ -1054,7 +1055,7 @@
"team": "demon",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 30,
"otherNight": 32,
"otherNightReminder": "The Vigormortis points to a player. That player dies. If a Minion, they keep their ability and one of their Townsfolk neighbours is poisoned.",
"reminders": ["Dead",
"Has ability",
@ -1069,7 +1070,7 @@
"team": "demon",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 28,
"otherNight": 30,
"otherNightReminder": "The No Dashii points to a player. That player dies.",
"reminders": ["Dead",
"Poisoned"],
@ -1083,11 +1084,11 @@
"team": "demon",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 29,
"otherNight": 31,
"otherNightReminder": "The Vortox points to a player. That player dies.",
"reminders": ["Dead"],
"setup": false,
"ability": "Each night*, choose a player; they die. Townsfolk abilities yield false info. Each day, if no-one is executed, evil wins."
"ability": "Each night*, choose a player: they die. Townsfolk abilities yield false info. Each day, if no-one is executed, evil wins."
},
{
"id": "barista",
@ -1127,7 +1128,7 @@
"otherNightReminder": "",
"reminders": [],
"setup": false,
"ability": "Each day, after the 1st execution, you nominate again."
"ability": "Each day, after the 1st execution, you may nominate again."
},
{
"id": "bonecollector",
@ -1156,14 +1157,27 @@
"setup": false,
"ability": "If you were funny today, you cannot die by exile."
},
{
"id": "noble",
"name": "Noble",
"edition": "",
"team": "townsfolk",
"firstNight": 44,
"firstNightReminder": "Point to 3 players including one evil player, in no particular order.",
"otherNight": 0,
"otherNightReminder": "",
"reminders": ["Seen"],
"setup": false,
"ability": "You start knowing 3 players, 1 and only 1 of which is evil."
},
{
"id": "bountyhunter",
"name": "Bounty Hunter",
"edition": "",
"team": "townsfolk",
"firstNight": 39,
"firstNight": 46,
"firstNightReminder": "Point to 1 evil player. Wake the townsfolk who is evil and show them the 'You are' card and the thumbs down evil sign.",
"otherNight": 60,
"otherNight": 64,
"otherNightReminder": "If the known evil player has died, point to another evil player. ",
"reminders": ["Known"],
"setup": true,
@ -1174,7 +1188,7 @@
"name": "Pixie",
"edition": "",
"team": "townsfolk",
"firstNight": 26,
"firstNight": 29,
"firstNightReminder": "Show the Pixie 1 in-play Townsfolk character token.",
"otherNight": 0,
"otherNightReminder": "",
@ -1188,9 +1202,9 @@
"name": "General",
"edition": "",
"team": "townsfolk",
"firstNight": 42,
"firstNight": 50,
"firstNightReminder": "Show the General thumbs up for good winning, thumbs down for evil winning or thumb to the side for neither.",
"otherNight": 63,
"otherNight": 69,
"otherNightReminder": "Show the General thumbs up for good winning, thumbs down for evil winning or thumb to the side for neither.",
"reminders": [],
"setup": false,
@ -1201,7 +1215,7 @@
"name": "Preacher",
"edition": "",
"team": "townsfolk",
"firstNight": 12,
"firstNight": 14,
"firstNightReminder": "The Preacher chooses a player. If a Minion is chosen, wake the Minion and show the 'This character selected you' card and then the Preacher token.",
"otherNight": 6,
"otherNightReminder": "The Preacher chooses a player. If a Minion is chosen, wake the Minion and show the 'This character selected you' card and then the Preacher token.",
@ -1214,9 +1228,9 @@
"name": "King",
"edition": "",
"team": "townsfolk",
"firstNight": 8,
"firstNight": 10,
"firstNightReminder": "Wake the Demon, show them the 'This character selected you' card, show the King token and point to the King player.",
"otherNight": 59,
"otherNight": 63,
"otherNightReminder": "If there are more dead than living, show the King a character token of a living player.",
"reminders": [],
"setup": false,
@ -1227,9 +1241,9 @@
"name": "Balloonist",
"edition": "",
"team": "townsfolk",
"firstNight": 38,
"firstNight": 45,
"firstNightReminder": "Choose a character type. Point to a player whose character is of that type. Place the Balloonist's Seen reminder next to that character.",
"otherNight": 58,
"otherNight": 62,
"otherNightReminder": "Choose a character type that does not yet have a Seen reminder next to a character of that type. Point to a player whose character is of that type, if there are any. Place the Balloonist's Seen reminder next to that character.",
"reminders": ["Seen Townsfolk",
"Seen Outsider",
@ -1244,9 +1258,9 @@
"name": "Cult Leader",
"edition": "",
"team": "townsfolk",
"firstNight": 40,
"firstNight": 48,
"firstNightReminder": "If the cult leader changed alignment, show them the thumbs up good signal of the thumbs down evil signal accordingly.",
"otherNight": 61,
"otherNight": 66,
"otherNightReminder": "If the cult leader changed alignment, show them the thumbs up good signal of the thumbs down evil signal accordingly.",
"reminders": [],
"setup": false,
@ -1259,7 +1273,7 @@
"team": "townsfolk",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 21,
"otherNight": 22,
"otherNightReminder": "The Lycanthrope points to a living player: if good, they die and no one else can die tonight.",
"reminders": ["Dead"],
"setup": false,
@ -1270,14 +1284,40 @@
"name": "Amnesiac",
"edition": "",
"team": "townsfolk",
"firstNight": 11,
"firstNight": 32,
"firstNightReminder": "Decide the Amnesiac's entire ability. If the Amnesiac's ability causes them to wake tonight: Wake the Amnesiac and run their ability.",
"otherNight": 5,
"otherNight": 47,
"otherNightReminder": "If the Amnesiac's ability causes them to wake tonight: Wake the Amnesiac and run their ability.",
"reminders": ["?"],
"setup": false,
"ability": "You do not know what your ability is. Each day, privately guess what it is: you learn how accurate you are."
},
{
"id": "nightwatchman",
"name": "Nightwatchman",
"edition": "",
"team": "townsfolk",
"firstNight": 47,
"firstNightReminder": "The Nightwatchman may point to a player. Wake that player, show the 'This character selected you' card and the Nightwatchman token, then point to the Nightwatchman player.",
"otherNight": 65,
"otherNightReminder": "The Nightwatchman may point to a player. Wake that player, show the 'This character selected you' card and the Nightwatchman token, then point to the Nightwatchman player.",
"reminders": ["No ability"],
"setup": false,
"ability": "Once per game, at night, choose a player: they learn who you are."
},
{
"id": "engineer",
"name": "Engineer",
"edition": "",
"team": "townsfolk",
"firstNight": 13,
"firstNightReminder": "The Engineer shows a 'no' head signal, or points to a Demon or points to the relevant number of Minions. If the Engineer chose characters, replace the Demon or Minions with the choices, then wake the relevant players and show them the You are card and the relevant character tokens.",
"otherNight": 5,
"otherNightReminder": "The Engineer shows a 'no' head signal, or points to a Demon or points to the relevant number of Minions. If the Engineer chose characters, replace the Demon or Minions with the choices, then wake the relevant players and show them the 'You are' card and the relevant character tokens.",
"reminders": ["No ability"],
"setup": false,
"ability": "Once per game, at night, choose which Minions or which Demon is in play."
},
{
"id": "fisherman",
"name": "Fisherman",
@ -1291,6 +1331,33 @@
"setup": false,
"ability": "Once per game, during the day, visit the Storyteller for some advice to help you win."
},
{
"id": "huntsman",
"name": "Huntsman",
"edition": "",
"team": "townsfolk",
"firstNight": 30,
"firstNightReminder": "The Huntsman shakes their head 'no' or points to a player. If they point to the Damsel, wake that player, show the 'You are' card and a not-in-play character token.",
"otherNight": 45,
"otherNightReminder": "The Huntsman shakes their head 'no' or points to a player. If they point to the Damsel, wake that player, show the 'You are' card and a not-in-play character token.",
"reminders": ["No ability"],
"setup": true,
"ability": "Once per game, at night, choose a living player: the Damsel, if chosen, becomes a not-in-play Townsfolk. [+the Damsel]"
},
{
"id": "alchemist",
"name": "Alchemist",
"edition": "",
"team": "townsfolk",
"firstNight": 3,
"firstNightReminder": "Show the Alchemist a not-in-play Minion token",
"otherNight": 0,
"otherNightReminder": "",
"reminders": [],
"remindersGlobal": ["Is the Alchemist"],
"setup": false,
"ability": "You have a not-in-play Minion ability."
},
{
"id": "farmer",
"name": "Farmer",
@ -1298,7 +1365,7 @@
"team": "townsfolk",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 43,
"otherNight": 48,
"otherNightReminder": "If a Farmer died tonight, choose another good player and make them the Farmer. Wake this player, show them the 'You are' card and the Farmer character token.",
"reminders": [],
"setup": false,
@ -1309,7 +1376,7 @@
"name": "Magician",
"edition": "",
"team": "townsfolk",
"firstNight": 0,
"firstNight": 5,
"firstNightReminder": "",
"otherNight": 0,
"otherNightReminder": "",
@ -1324,7 +1391,7 @@
"team": "townsfolk",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 41,
"otherNight": 44,
"otherNightReminder": "If the King was killed by the Demon, wake the Choirboy and point to the Demon player.",
"reminders": [],
"setup": true,
@ -1335,7 +1402,7 @@
"name": "Poppy Grower",
"edition": "",
"team": "townsfolk",
"firstNight": 3,
"firstNight": 4,
"firstNightReminder": "Do not inform the Demon/Minions who each other are",
"otherNight": 3,
"otherNightReminder": "If the Poppy Grower has died, show the Minions/Demon who each other are.",
@ -1343,6 +1410,19 @@
"setup": false,
"ability": "Minions & Demons do not know each other. If you die, they learn who each other are that night."
},
{
"id": "atheist",
"name": "Atheist",
"edition": "",
"team": "townsfolk",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 0,
"otherNightReminder": "",
"reminders": [],
"setup": true,
"ability": "The Storyteller can break the game rules & if executed, good wins, even if you are dead. [No evil characters]"
},
{
"id": "cannibal",
"name": "Cannibal",
@ -1362,7 +1442,7 @@
"name": "Snitch",
"edition": "",
"team": "outsider",
"firstNight": 5,
"firstNight": 7,
"firstNightReminder": "After Minion info wake each Minion and show them three not-in-play character tokens. These may be the same or different to each other and the ones shown to the Demon.",
"otherNight": 0,
"otherNightReminder": "",
@ -1377,12 +1457,26 @@
"team": "outsider",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 36,
"otherNight": 39,
"otherNightReminder": "If a good living neighbour is drunk or poisoned, the Acrobat player dies.",
"reminders": ["Dead"],
"setup": false,
"ability": "Each night*, if either good living neighbour is drunk or poisoned, you die."
},
{
"id": "puzzlemaster",
"name": "Puzzlemaster",
"edition": "",
"team": "outsider",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 0,
"otherNightReminder": "",
"reminders": ["Drunk",
"Guess used"],
"setup": false,
"ability": "1 player is drunk, even if you die. If you guess (once) who it is, learn the Demon player, but guess wrong & get false info."
},
{
"id": "heretic",
"name": "Heretic",
@ -1396,6 +1490,32 @@
"setup": false,
"ability": "Whoever wins, loses & whoever loses, wins, even if you are dead."
},
{
"id": "damsel",
"name": "Damsel",
"edition": "",
"team": "outsider",
"firstNight": 31,
"firstNightReminder": "Wake all the Minions, show them the 'This character selected you' card and the Damsel token.",
"otherNight": 46,
"otherNightReminder": "If selected by the Huntsman, wake the Damsel, show 'You are' card and a not-in-play Townsfolk token.",
"reminders": ["Guess used"],
"setup": false,
"ability": "All Minions know you are in play. If a Minion publicly guesses you (once), your team loses."
},
{
"id": "golem",
"name": "Golem",
"edition": "",
"team": "outsider",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 0,
"otherNightReminder": "",
"reminders": ["Can not nominate"],
"setup": false,
"ability": "You may only nominate once per game. When you do, if the nominee is not the Demon, they die."
},
{
"id": "politician",
"name": "Politician",
@ -1414,7 +1534,7 @@
"name": "Widow",
"edition": "",
"team": "minion",
"firstNight": 16,
"firstNight": 18,
"firstNightReminder": "Show the Grimoire to the Widow for as long as they need. The Widow points to a player. That player is poisoned. Wake a good player. Show the 'These characters are in play' card, then the Widow character token.",
"otherNight": 0,
"otherNightReminder": "",
@ -1423,6 +1543,32 @@
"setup": false,
"ability": "On your 1st night, look at the Grimoire and choose a player: they are poisoned. 1 good player knows a Widow is in play."
},
{
"id": "fearmonger",
"name": "Fearmonger",
"edition": "",
"team": "minion",
"firstNight": 26,
"firstNightReminder": "The Fearmonger points to a player. Place the Fear token next to that player and announce that a new player has been selected with the Fearmonger ability.",
"otherNight": 17,
"otherNightReminder": "The Fearmonger points to a player. If different from the previous night, place the Fear token next to that player and announce that a new player has been selected with the Fearmonger ability.",
"reminders": ["Fear"],
"setup": false,
"ability": "Each night, choose a player. If you nominate & execute them, their team loses. All players know if you choose a new player."
},
{
"id": "psychopath",
"name": "Psychopath",
"edition": "",
"team": "minion",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 0,
"otherNightReminder": "",
"reminders": [],
"setup": false,
"ability": "Each day, before nominations, you may publicly choose a player: they die. If executed, you only die if you lose roshambo."
},
{
"id": "goblin",
"name": "Goblin",
@ -1437,28 +1583,28 @@
"ability": "If you publicly claim to be the Goblin when nominated & are executed that day, your team wins."
},
{
"id": "mezepheles",
"name": "Mezepheles",
"id": "mephit",
"name": "Mephit",
"edition": "",
"team": "minion",
"firstNight": 24,
"firstNightReminder": "Show the Mezepheles their secret word.",
"otherNight": 17,
"otherNightReminder": "Wake the 1st good player that said the Mezepheles' secret word and show them the 'You are' card and the thumbs down evil signal.",
"firstNight": 27,
"firstNightReminder": "Show the Mephit their secret word.",
"otherNight": 18,
"otherNightReminder": "Wake the 1st good player that said the Mephit's secret word and show them the 'You are' card and the thumbs down evil signal.",
"reminders": ["Turns evil",
"No ability"],
"setup": false,
"ability": "You start knowing a secret word. The 1st good player to say this word becomes evil that night."
},
{
"id": "mephit",
"name": "Mephit",
"id": "mezepheles",
"name": "Mezepheles",
"edition": "",
"team": "minion",
"firstNight": 24,
"firstNightReminder": "Show the Mephit their secret word.",
"otherNight": 17,
"otherNightReminder": "Wake the 1st good player that said the Mephit's secret word and show them the 'You are' card and the thumbs down evil signal.",
"firstNight": 27,
"firstNightReminder": "Show the Mezepheles their secret word.",
"otherNight": 18,
"otherNightReminder": "Wake the 1st good player that said the Mezepheles' secret word and show them the 'You are' card and the thumbs down evil signal.",
"reminders": ["Turns evil",
"No ability"],
"setup": false,
@ -1469,7 +1615,7 @@
"name": "Marionette",
"edition": "",
"team": "minion",
"firstNight": 10,
"firstNight": 12,
"firstNightReminder": "Select one of the good players next to the Demon and place the Is the Marionette reminder token. Wake the Demon and show them the Marionette.",
"otherNight": 0,
"otherNightReminder": "",
@ -1493,33 +1639,48 @@
},
{
"id": "lilmonsta",
"name": "Lil Monsta",
"name": "Lil' Monsta",
"edition": "",
"team": "demon",
"firstNight": 14,
"firstNight": 15,
"firstNightReminder": "Wake all Minions together, allow them to vote by pointing at who they want to babysit Lil' Monsta.",
"otherNight": 33,
"otherNight": 35,
"otherNightReminder": "Wake all Minions together, allow them to vote by pointing at who they want to babysit Lil' Monsta. Choose a player, that player dies.",
"reminders": [],
"remindersGlobal": ["Is the Demon",
"Dead"],
"setup": true,
"ability": "Each night, Minions choose who babysits Lil Monsta's token & \"is the Demon\". A player dies each night*. [+1 Minion]"
"ability": "Each night, Minions choose who babysits Lil' Monsta's token & \"is the Demon\". A player dies each night*. [+1 Minion]"
},
{
"id": "lleech",
"name": "Lleech",
"edition": "",
"team": "demon",
"firstNight": 13,
"firstNight": 16,
"firstNightReminder": "The Lleech points to a player. Place the Poisoned reminder token.",
"otherNight": 32,
"otherNight": 34,
"otherNightReminder": "The Lleech points to a player. That player dies.",
"reminders": ["Dead",
"Poisoned"],
"setup": false,
"ability": "Each night*, choose a player: they die. You start by choosing an alive player: they are poisoned - you die if & only if they die."
},
{
"id": "alhadikhia",
"name": "Al-Hadikhia",
"edition": "",
"team": "demon",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 33,
"otherNightReminder": "The Al-Hadikhia chooses 3 players. Announce the first player, wake them to nod yes to live or shake head no to die, kill or resurrect accordingly, then put to sleep and announce the next player. If all 3 are alive after this, all 3 die.",
"reminders": ["1", "2", "3",
"Chose death",
"Chose life"],
"setup": false,
"ability": "Each night*, choose 3 players (all players learn who): each silently chooses to live or die, but if all live, all die."
},
{
"id": "legion",
"name": "Legion",
@ -1527,7 +1688,7 @@
"team": "demon",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 31,
"otherNight": 23,
"otherNightReminder": "Choose a player, that player dies.",
"reminders": ["Dead",
"About to die"],
@ -1539,9 +1700,9 @@
"name": "Leviathan",
"edition": "",
"team": "demon",
"firstNight": 46,
"firstNight": 54,
"firstNightReminder": "Place the Leviathan 'Day 1' marker. Announce 'The Leviathan is in play; this is Day 1.'",
"otherNight": 67,
"otherNight": 73,
"otherNightReminder": "Change the Leviathan Day reminder for the next day.",
"reminders": ["Day 1",
"Day 2",
@ -1552,6 +1713,19 @@
"setup": false,
"ability": "If more than 1 good player is executed, you win. All players know you are in play. After day 5, evil wins."
},
{
"id": "riot",
"name": "Riot",
"edition": "",
"team": "demon",
"firstNight": 0,
"firstNightReminder": "",
"otherNight": 0,
"otherNightReminder": "",
"reminders": [],
"setup": true,
"ability": "Nominees die, but may nominate again immediately (on day 3, they must). After day 3, evil wins. [All Minions are Riot]"
},
{
"id": "gangster",
"name": "Gangster",

View File

@ -214,7 +214,7 @@ export default new Vuex.Store({
state.roles.get(role.id) ||
Object.assign({}, customRole, role)
)
// default empty icons and placeholders
// default empty icons and placeholders, clean up firstNight / otherNight
.map(role => {
if (rolesJSONbyId.get(role.id)) return role;
role.imageAlt = // map team to generic icon
@ -225,6 +225,8 @@ export default new Vuex.Store({
demon: "evil",
fabled: "fabled"
}[role.team] || "custom";
role.firstNight = Math.abs(role.firstNight);
role.otherNight = Math.abs(role.otherNight);
return role;
})
// filter out roles that don't match an existing role and also don't have name/ability/team

View File

@ -1,7 +1,7 @@
class LiveSession {
constructor(store) {
this._wss = "wss://live.clocktower.online:8080/";
//this._wss = "wss://localhost:8081/";
// this._wss = "ws://localhost:8081/"; // uncomment if using local server with NODE_ENV=development
this._socket = null;
this._isSpectator = true;
this._gamestate = [];