diff --git a/CHANGELOG.md b/CHANGELOG.md index 5afd997..3c03df0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Release Notes +### Version 2.8.0 +- added hands-off live session support for homebrew / custom characters again! +- added custom image opt-in that will prevent any (potentially malicious / harmful) images from loading until a player manually allows them to + +--- + +## Version 2.7.0 +- added support for assigning duplicate characters to more than one player (like Legion) +- further live session bandwidth optimizations +- sessions can now be joined by pasting the whole link into the popup (thanks @davotronic5000) +- fabled night order bug fixed +- added Legion to list of available characters (thanks @eddgabriel) +- added support for mp4/webm video backgrounds +- added tooltips to night order popup + +--- + ## Version 2.6.0 - night mode can be toggeled with [S] now (thanks @davotronic5000) - night order shows which players are dead diff --git a/README.md b/README.md index 73306ba..5c1a7e0 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,9 @@ If you want to learn more about how to use the website as a player, [JayBotC](ht - Public Town Square and Storyteller Grimoire (toggle with **shortcut \[G\]**) - Supports custom script JSON generated by the [Script Tool](https://bloodontheclocktower.com/script) - Live Session for Storyteller / Players including live voting and character distribution! -- Includes all 3 base editions, Travelers and Fabled +- Includes all 3 base editions, Travelers and Fabled plus all officially spoiled characters so far! - Night sheet and reminder text for each character ability to help storytellers +- Full homebrew support for hosting and playing games with your own sets of characters - Many other customization options! ### Custom Script Support @@ -44,8 +45,7 @@ character: This will provide your local Grimoire (and those of your live session players) with more information to show about your custom script - instead of "Custom Script" it would show "Deadly Penance Day" on the character reference sheet, -for example. The logo is shown only locally, if you want your players to see it as well, they will have to upload the -same JSON file that you used. +for example. The logo will be shown to your players after they have enabled custom images in the Grimoire menu. ### Custom Character Support @@ -84,8 +84,10 @@ For base game characters, it is sufficient to only provide the ID, similar to wh **Required properties:** `id`, `name`, `team`, `ability` -- **id**: the internal ID for this character, without spaces or special characters -- **image**: a URL to a PNG of the character token icon (should have a transparent background!) +- **id**: the internal ID for this character, without spaces or special characters
+ _Note_: this ID needs to be unique and can't be the same as any ID already used by an existing character, otherwise the custom character will be overwritten with the existing role! +- **image**: a URL to a PNG of the character token icon (should have a transparent background!)
+ _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 @@ -97,9 +99,6 @@ For base game characters, it is sufficient to only provide the ID, similar to wh - **team**: the team of the character, has to be one of `townsfolk`, `outsider`, `minion`, `demon` or `traveler` - **ability**: the displayed ability text of the character -_Note:_ in order to use custom characters in live sessions, your players have to load the same JSON file that the storyteller -has loaded before joining the live session. - ## [Code of Conduct](CODE_OF_CONDUCT.md) ## [Contributing](CONTRIBUTING.md) diff --git a/package-lock.json b/package-lock.json index 55e9914..6f53472 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "townsquare", - "version": "2.6.0", + "version": "2.8.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 4b379d7..8eabedb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "townsquare", - "version": "2.6.0", + "version": "2.8.0", "description": "Blood on the Clocktower Town Square", "author": "Steffen Baumgart", "scripts": { diff --git a/server/index.js b/server/index.js index 0a82715..2a8ebc1 100644 --- a/server/index.js +++ b/server/index.js @@ -150,40 +150,63 @@ wss.on("connection", function connection(ws, req) { .substr(1) .split(",", 1) .pop(); - // don't log ping messages - if (messageType !== '"ping"') { - console.log(new Date(), wss.clients.size, ws.channel, ws.playerId, data); - } - // handle "direct" messages differently - if (messageType === '"direct"') { - try { - const dataToPlayer = JSON.parse(data)[1]; + switch (messageType) { + case '"ping"': + // ping messages will only be sent host -> all or all -> host channels[ws.channel].forEach(function each(client) { if ( client !== ws && client.readyState === WebSocket.OPEN && - dataToPlayer[client.playerId] + (ws.playerId === "host" || client.playerId === "host") ) { - client.send(JSON.stringify(dataToPlayer[client.playerId])); + client.send( + data.replace(/latency/, (client.latency || 0) + (ws.latency || 0)) + ); metrics.messages_outgoing.inc(); } }); - } catch (e) { - console.log("error parsing direct message JSON", e); - } - } else { - // all other messages - channels[ws.channel].forEach(function each(client) { - if (client !== ws && client.readyState === WebSocket.OPEN) { - // inject latency between both clients if ping message - if (messageType === '"ping"' && client.latency && ws.latency) { - client.send(data.replace(/latency/, client.latency + ws.latency)); - } else { - client.send(data); - } - metrics.messages_outgoing.inc(); + break; + case '"direct"': + // handle "direct" messages differently + console.log( + new Date(), + wss.clients.size, + ws.channel, + ws.playerId, + data + ); + try { + const dataToPlayer = JSON.parse(data)[1]; + channels[ws.channel].forEach(function each(client) { + if ( + client !== ws && + client.readyState === WebSocket.OPEN && + dataToPlayer[client.playerId] + ) { + client.send(JSON.stringify(dataToPlayer[client.playerId])); + metrics.messages_outgoing.inc(); + } + }); + } catch (e) { + console.log("error parsing direct message JSON", e); } - }); + break; + default: + // all other messages + console.log( + new Date(), + wss.clients.size, + ws.channel, + ws.playerId, + data + ); + channels[ws.channel].forEach(function each(client) { + if (client !== ws && client.readyState === WebSocket.OPEN) { + client.send(data); + metrics.messages_outgoing.inc(); + } + }); + break; } }); }); diff --git a/src/App.vue b/src/App.vue index 4c8a836..bb5bc65 100644 --- a/src/App.vue +++ b/src/App.vue @@ -10,6 +10,13 @@ : '' }" > +
@@ -299,6 +306,14 @@ ul { } } +/* video background */ +video#background { + position: absolute; + width: 100%; + height: 100%; + object-fit: cover; +} + /* Night phase backdrop */ #app > .backdrop { position: absolute; diff --git a/src/assets/icons/legion.png b/src/assets/icons/legion.png new file mode 100644 index 0000000..3adcdbc Binary files /dev/null and b/src/assets/icons/legion.png differ diff --git a/src/assets/icons/minion.png b/src/assets/icons/minion.png new file mode 100644 index 0000000..ef0ccb1 Binary files /dev/null and b/src/assets/icons/minion.png differ diff --git a/src/assets/icons/outsider.png b/src/assets/icons/outsider.png new file mode 100644 index 0000000..71b7a58 Binary files /dev/null and b/src/assets/icons/outsider.png differ diff --git a/src/assets/icons/snitch.png b/src/assets/icons/snitch.png new file mode 100644 index 0000000..df49832 Binary files /dev/null and b/src/assets/icons/snitch.png differ diff --git a/src/components/Menu.vue b/src/components/Menu.vue index 79715a5..fa46beb 100644 --- a/src/components/Menu.vue +++ b/src/components/Menu.vue @@ -69,11 +69,21 @@ /> +
  • + Show Custom Images + +
  • Background image
  • -
  • +
  • Mute Sounds