finished custom script meta info

This commit is contained in:
Steffen 2020-12-20 22:01:56 +01:00
parent 398fe89bb7
commit bbb95a6373
6 changed files with 108 additions and 41 deletions

View File

@ -19,7 +19,30 @@ To set up a game as the host, check out this tutorial video:
- Night sheet and reminder text for each character ability to help storytellers
- Many other customization options!
### Custom Characters
### Custom Script Support
Any custom script generated by the official [Script Tool](https://bloodontheclocktower.com/script) 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:
```json
[
{
"id": "_meta",
"name": "Deadly Penance Day",
"author": "TPI",
"logo": "https://url.to/your/logo.png"
}
]
```
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.
### Custom Character Support
In order to add custom characters to your local Grimoire, you need to create a JSON definition for them,
similar to what is provided in the [`roles.json`](https://github.com/bra1n/townsquare/blob/main/src/roles.json) for the 3 base editions. Here's an example of how such a character

View File

@ -2,7 +2,7 @@
<ul class="info">
<li
class="edition"
:class="['edition-' + edition]"
:class="['edition-' + edition.id]"
:style="{
backgroundImage: `url(${edition.logo ||
require('../assets/editions/' + edition.id + '.png')})`
@ -12,40 +12,59 @@
Please add more players!
</li>
<li>
{{ players.length }} <font-awesome-icon class="players" icon="users" />
{{ teams.alive }} <font-awesome-icon class="alive" icon="heartbeat" />
{{ teams.votes }} <font-awesome-icon class="votes" icon="vote-yea" />
<span class="meta" v-if="!edition.isOfficial">
{{ edition.name }}
{{ edition.author ? "by " + edition.author : "" }}
</span>
<span>
{{ players.length }} <font-awesome-icon class="players" icon="users" />
</span>
<span>
{{ teams.alive }}
<font-awesome-icon class="alive" icon="heartbeat" />
</span>
<span>
{{ teams.votes }} <font-awesome-icon class="votes" icon="vote-yea" />
</span>
</li>
<li v-if="players.length - teams.traveler >= 5">
{{ teams.townsfolk }}
<font-awesome-icon class="townsfolk" icon="user-friends" />
{{ teams.outsider }}
<font-awesome-icon
class="outsider"
:icon="teams.outsider > 1 ? 'user-friends' : 'user'"
/>
{{ teams.minion }}
<font-awesome-icon
class="minion"
:icon="teams.minion > 1 ? 'user-friends' : 'user'"
/>
{{ teams.demon }}
<font-awesome-icon
class="demon"
:icon="teams.demon > 1 ? 'user-friends' : 'user'"
/>
<template v-if="teams.traveler">
<span>
{{ teams.townsfolk }}
<font-awesome-icon class="townsfolk" icon="user-friends" />
</span>
<span>
{{ teams.outsider }}
<font-awesome-icon
class="outsider"
:icon="teams.outsider > 1 ? 'user-friends' : 'user'"
/>
</span>
<span>
{{ teams.minion }}
<font-awesome-icon
class="minion"
:icon="teams.minion > 1 ? 'user-friends' : 'user'"
/>
</span>
<span>
{{ teams.demon }}
<font-awesome-icon
class="demon"
:icon="teams.demon > 1 ? 'user-friends' : 'user'"
/>
</span>
<span v-if="teams.traveler">
{{ teams.traveler }}
<font-awesome-icon
class="traveler"
:icon="teams.traveler > 1 ? 'user-friends' : 'user'"
/>
</template>
<template v-if="grimoire.isNight">
</span>
<span v-if="grimoire.isNight">
<br />
Night phase
<font-awesome-icon :icon="['fas', 'cloud-moon']" />
</template>
</span>
</li>
</ul>
</template>
@ -94,12 +113,25 @@ export default {
background-size: auto 100%;
li {
display: block;
font-weight: bold;
text-align: center;
padding: 0 5px;
width: 100%;
filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.7));
display: flex;
flex-wrap: wrap;
justify-content: center;
text-shadow: 0 2px 1px black, 0 -2px 1px black, 2px 0 1px black,
-2px 0 1px black;
span {
white-space: nowrap;
}
.meta {
text-align: center;
flex-basis: 100%;
font-family: PiratesBay, sans-serif;
font-weight: normal;
}
svg {
margin-right: 10px;

View File

@ -93,11 +93,11 @@ export default {
scripts: [
[
"Deadly Penance Day",
"https://gist.githubusercontent.com/bra1n/0337cc44c6fd2c44f7589256ed5486d2/raw/4a7a1545004620146f47583cde4b05f77dd9b6d2/penanceday.json"
"https://gist.githubusercontent.com/bra1n/0337cc44c6fd2c44f7589256ed5486d2/raw/16be38fa3c01aaf49827303ac80577bdb52c0b25/penanceday.json"
],
[
"Catfishing 9.0",
"https://gist.githubusercontent.com/bra1n/8a5ec41a7bbf945f6b7dfc1cef72b569/raw/998767f82badc48cbb9c284765ad36330f7e28f6/catfishing.json"
"https://gist.githubusercontent.com/bra1n/8a5ec41a7bbf945f6b7dfc1cef72b569/raw/fed370d55554e0d83e9d56023c230099f41d0660/catfishing.json"
],
[
"On Thin Ice (Teensyville)",
@ -158,12 +158,20 @@ export default {
},
parseRoles(roles) {
if (!roles || !roles.length) return;
const metaIndex = roles.findIndex(({ id }) => id === "_meta");
let meta = {};
if (metaIndex > -1) {
meta = roles.splice(metaIndex, 1).pop();
}
const customRoles = roles.map(role => {
role.id = role.id.toLocaleLowerCase().replace(/[^a-z0-9]/g, "");
return role;
});
this.$store.commit("setCustomRoles", customRoles);
this.$store.commit("setEdition", { id: "custom" });
this.$store.commit(
"setEdition",
Object.assign({}, meta, { id: "custom" })
);
// check for fabled and set those too, if present
if (customRoles.some(({ id }) => this.$store.state.fabled.has(id))) {
const fabled = [];

View File

@ -34,7 +34,9 @@ export default {
gamestate: function() {
return JSON.stringify({
bluffs: this.players.bluffs.map(({ id }) => id),
edition: this.edition,
edition: this.edition.isOfficial
? { id: this.edition.id }
: this.edition,
roles: this.edition.isOfficial ? "" : this.$store.getters.customRoles,
fabled: this.players.fabled.map(({ id }) => id),
players: this.players.players.map(player => ({
@ -66,12 +68,12 @@ export default {
try {
const data = JSON.parse(this.input || this.gamestate);
const { bluffs, edition, roles, fabled, players } = data;
if (edition) {
this.$store.commit("setEdition", edition);
}
if (roles) {
this.$store.commit("setCustomRoles", roles);
}
if (edition) {
this.$store.commit("setEdition", edition);
}
if (bluffs.length) {
bluffs.forEach((role, index) => {
this.$store.commit("players/setBluff", {

View File

@ -2,7 +2,7 @@
{
"id": "tb",
"name": "Trouble Brewing",
"hasTravelers": true,
"author": "The Pandemonium Institute",
"description": "Clouds roll in over Ravenswood Bluff, engulfing this sleepy town and its superstitious inhabitants in foreboding shadow. Freshly-washed clothes dance eerily on lines strung between cottages. Chimneys cough plumes of smoke into the air. Exotic scents waft through cracks in windows and under doors, as hidden cauldrons lay bubbling. An unusually warm Autumn breeze wraps around vine-covered walls and whispers ominously to those brave enough to walk the cobbled streets.\n\nAnxious mothers call their children home from play, as thunder begins to clap on the horizon. If you listen more closely, however, noises stranger still can be heard echoing from the neighbouring forest. Under the watchful eye of a looming monastery, silhouetted figures skip from doorway to doorway. Those who can read the signs know there is... Trouble Brewing.",
"level": "Beginner",
"roles": [],
@ -11,7 +11,7 @@
{
"id": "bmr",
"name": "Bad Moon Rising",
"hasTravelers": true,
"author": "The Pandemonium Institute",
"description": "The sun is swallowed by a jagged horizon as another winter's day surrenders to the night. Flecks of orange and red decay into deeper browns, the forest transforming in silent anticipation of the coming snow.\n\nRavenous wolves howl from the bowels of a rocky crevasse beyond the town borders, sending birds scattering from their cozy rooks. Travelers hurry into the inn, seeking shelter from the gathering chill. They warm themselves with hot tea, sweet strains of music and hearty ale, unaware that strange and nefarious eyes stalk them from the ruins of this once great city.\n\nTonight, even the livestock know there is a... Bad Moon Rising.",
"level": "Intermediate",
"roles": [],
@ -20,7 +20,7 @@
{
"id": "snv",
"name": "Sects & Violets",
"hasTravelers": true,
"author": "The Pandemonium Institute",
"description": "Vibrant spring gives way to a warm and inviting summer. Flowers of every description blossom as far as the eye can see, tenderly nurtured in public gardens and window boxes overlooking the lavish promenade. Birds sing, artists paint and philosophers ponder life's greatest mysteries inside a bustling tavern as a circus pitches its endearingly ragged tent on the edge of town.\n\nAs the townsfolk bask in frivolity and mischief, indulging themselves in fine entertainment and even finer wine, dark and clandestine forces are assembling. Witches and cults lurk in majestic ruins on the fringes of the community, hosting secret meetings in underground caves and malevolently plotting the downfall of Ravenswood Bluff and its revelers.\n\nThe time is ripe for... Sects & Violets.",
"level": "Intermediate",
"roles": [],
@ -29,7 +29,7 @@
{
"id": "luf",
"name": "Laissez un Faire",
"hasTravelers": false,
"author": "The Pandemonium Institute",
"description": "",
"level": "Veteran",
"roles": ["balloonist", "savant", "amnesiac", "fisherman", "artist", "cannibal", "mutant", "lunatic", "widow", "goblin", "leviathan"],

View File

@ -324,7 +324,9 @@ class LiveSession {
roles = Array.from(this._store.state.roles.keys());
}
this._send("edition", {
edition,
edition: edition.isOfficial
? { id: edition.id }
: Object.assign({}, edition, { logo: "" }),
...(roles ? { roles } : {})
});
}