added support for custom (base character) scripts

This commit is contained in:
Steffen 2020-05-15 23:36:45 +02:00
parent 8fcf12d656
commit 061e7565e8
No known key found for this signature in database
GPG Key ID: 764D74E98267DFC6
11 changed files with 180 additions and 25 deletions

View File

@ -86,6 +86,12 @@ export default {
url("assets/fonts/papyrus.svg#PapyrusW01") format("svg"); /* iOS 4.1- */ url("assets/fonts/papyrus.svg#PapyrusW01") format("svg"); /* iOS 4.1- */
} }
@font-face {
font-family: PiratesBay;
src: url("assets/fonts/piratesbay.ttf");
font-display: swap;
}
html, html,
body { body {
font-size: 1.2em; font-size: 1.2em;
@ -121,6 +127,9 @@ h4,
h5 { h5 {
margin: 0; margin: 0;
text-align: center; text-align: center;
font-family: PiratesBay, sans-serif;
letter-spacing: 1px;
font-weight: normal;
} }
ul { ul {

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

View File

@ -1,12 +1,12 @@
<template> <template>
<div class="intro" > <div class="intro">
<img src="static/apple-icon.png" alt="" /> <img src="static/apple-icon.png" alt="" />
Welcome to the (unofficial) Welcome to the (unofficial)
<b> Virtual Blood on the Clocktower Town Square</b>!<br /> <b> Virtual Blood on the Clocktower Town Square</b>!<br />
Please add more players through the Please add more players through the
<span class="button"> <span class="button" @click="toggleMenu">
<font-awesome-icon icon="cog" @click="toggleMenu" /> Menu <font-awesome-icon icon="cog" /> Menu
</span> </span>
on the top right or by pressing <b>[A]</b>.<br /> on the top right or by pressing <b>[A]</b>.<br />
This project is free and open source and can be found on This project is free and open source and can be found on
<a href="https://github.com/bra1n/townsquare" target="_blank">GitHub</a>. <a href="https://github.com/bra1n/townsquare" target="_blank">GitHub</a>.

View File

@ -317,9 +317,10 @@ export default {
} }
.headline { .headline {
font-family: PiratesBay, sans-serif;
letter-spacing: 1px;
padding: 5px 10px; padding: 5px 10px;
text-align: center; text-align: center;
font-weight: bold;
background: linear-gradient( background: linear-gradient(
to right, to right,
$townsfolk 0%, $townsfolk 0%,

View File

@ -243,6 +243,10 @@ export default {
pointer-events: none; pointer-events: none;
} }
#townsquare.spectator & {
pointer-events: none;
}
#townsquare:not(.spectator) &:hover:before { #townsquare:not(.spectator) &:hover:before {
opacity: 0.5; opacity: 0.5;
top: -10px; top: -10px;

View File

@ -4,18 +4,60 @@
v-show="modals.edition" v-show="modals.edition"
@close="toggleModal('edition')" @close="toggleModal('edition')"
> >
<h3>Select an edition:</h3> <div v-if="!isCustom">
<ul class="editions"> <h3>Select an edition:</h3>
<li <ul class="editions">
v-for="edition in editions" <li
class="edition" v-for="edition in editions"
v-bind:class="['edition-' + edition.id]" class="edition"
v-bind:key="edition.id" v-bind:class="['edition-' + edition.id]"
@click="setEdition(edition.id)" v-bind:key="edition.id"
@click="setEdition(edition.id)"
>
{{ edition.name }}
</li>
<li class="edition edition-custom" @click="isCustom = true">
Custom Edition
</li>
</ul>
</div>
<div class="custom" v-else>
<h3>Select a custom edition</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"
>Script Tool</a
> >
{{ edition.name }} and then upload the generated "custom-list.json" either directly here or
</li> provide a URL to such a hosted JSON file.<br />
</ul> <h3>Some custom Teensyville scripts:</h3>
<ul class="scripts">
<li
v-for="(script, index) in scripts"
v-bind:key="index"
@click="handleURL(script[1])"
>
{{ script[0] }}
</li>
</ul>
<input
type="file"
ref="upload"
accept="application/json"
@change="handleUpload"
/>
<div class="button-group">
<div class="button" @click="openUpload">
<font-awesome-icon icon="file-upload" /> Upload JSON
</div>
<div class="button" @click="promptURL">
<font-awesome-icon icon="link" /> Enter URL
</div>
<div class="button" @click="isCustom = false">
<font-awesome-icon icon="undo" /> Back
</div>
</div>
</div>
</Modal> </Modal>
</template> </template>
@ -30,11 +72,57 @@ export default {
}, },
data: function() { data: function() {
return { return {
editions: editionJSON editions: editionJSON,
isCustom: false,
scripts: [
[
"On Thin Ice",
"https://gist.githubusercontent.com/bra1n/8dacd9f2abc6f428331ea1213ab153f5/raw/9758aff4b59965dc7a094db549d950be5a26b571/custom-script.json"
],
[
"Race To The Bottom",
"https://gist.githubusercontent.com/bra1n/63e1354cb3dc9d4032bcd0623dc48888/raw/5be4df8386ec61e3a98c32be77f8cac3f8414379/custom-script.json"
]
]
}; };
}, },
computed: mapState(["modals"]), computed: mapState(["modals"]),
methods: mapMutations(["toggleModal", "setEdition"]) methods: {
openUpload() {
this.$refs.upload.click();
},
handleUpload() {
const file = this.$refs.upload.files[0];
if (file && file.size) {
const reader = new FileReader();
reader.addEventListener("load", () => {
this.parseScript(JSON.parse(reader.result));
});
reader.readAsText(file);
}
},
promptURL() {
const url = prompt("Enter URL to a custom-script.JSON");
if (url) {
this.handleURL(url);
}
},
async handleURL(url) {
const res = await fetch(url);
if (res && res.json) {
const script = await res.json();
this.parseScript(script);
}
},
parseScript(script) {
if (!script || !script.length) return;
const roles = script.map(({ id }) => id);
this.$store.commit("setRoles", roles);
this.$store.commit("setEdition", "custom");
this.isCustom = false;
},
...mapMutations(["toggleModal", "setEdition"])
}
}; };
</script> </script>
@ -63,15 +151,16 @@ export default {
} }
ul.editions .edition { ul.editions .edition {
font-family: PiratesBay, sans-serif;
letter-spacing: 1px;
text-align: center; text-align: center;
padding-top: 100px; padding-top: 100px;
background-position: center center; background-position: center center;
background-size: 100% auto; background-size: 100% auto;
background-repeat: no-repeat; background-repeat: no-repeat;
width: 200px; width: 30%;
margin: 5px; margin: 5px;
font-size: 120%; font-size: 120%;
font-weight: bold;
text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000,
1px 1px 0 #000, 0 0 5px rgba(0, 0, 0, 0.75); 1px 1px 0 #000, 0 0 5px rgba(0, 0, 0, 0.75);
cursor: pointer; cursor: pointer;
@ -79,4 +168,23 @@ ul.editions .edition {
color: red; color: red;
} }
} }
.custom {
text-align: center;
input[type="file"] {
display: none;
}
.scripts {
list-style-type: disc;
font-size: 120%;
cursor: pointer;
display: block;
width: 50%;
text-align: left;
margin: 10px auto;
li:hover {
color: red;
}
}
}
</style> </style>

View File

@ -23,7 +23,10 @@ import {
faBroadcastTower, faBroadcastTower,
faCopy, faCopy,
faExchangeAlt, faExchangeAlt,
faHandPointRight faHandPointRight,
faFileUpload,
faLink,
faUndo
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
@ -48,7 +51,10 @@ library.add(
faBroadcastTower, faBroadcastTower,
faCopy, faCopy,
faExchangeAlt, faExchangeAlt,
faHandPointRight faHandPointRight,
faFileUpload,
faLink,
faUndo
); );
Vue.component("font-awesome-icon", FontAwesomeIcon); Vue.component("font-awesome-icon", FontAwesomeIcon);

View File

@ -86,6 +86,7 @@ export default new Vuex.Store({
} }
}, },
toggleModal({ modals }, name) { toggleModal({ modals }, name) {
console.log("toggle", name);
modals[name] = !modals[name]; modals[name] = !modals[name];
}, },
updateScreenshot({ grimoire }, status) { updateScreenshot({ grimoire }, status) {
@ -97,10 +98,20 @@ export default new Vuex.Store({
grimoire.isScreenshot = false; grimoire.isScreenshot = false;
} }
}, },
setRoles(state, roles) {
state.roles = new Map(
rolesJSON
.filter(r => roles.includes(r.id))
.sort((a, b) => b.team.localeCompare(a.team))
.map(role => [role.id, role])
);
},
setEdition(state, edition) { setEdition(state, edition) {
state.edition = edition; state.edition = edition;
state.modals.edition = false; state.modals.edition = false;
state.roles = getRolesByEdition(edition); if (edition !== "custom") {
state.roles = getRolesByEdition(edition);
}
} }
}, },
plugins: [persistence, session] plugins: [persistence, session]

View File

@ -10,6 +10,9 @@ module.exports = store => {
// this will initialize state.roles! // this will initialize state.roles!
store.commit("setEdition", localStorage.edition); store.commit("setEdition", localStorage.edition);
} }
if (localStorage.roles !== undefined) {
store.commit("setRoles", JSON.parse(localStorage.roles));
}
if (localStorage.bluffs !== undefined) { if (localStorage.bluffs !== undefined) {
JSON.parse(localStorage.bluffs).forEach((role, index) => { JSON.parse(localStorage.bluffs).forEach((role, index) => {
store.commit("setBluff", { store.commit("setBluff", {
@ -50,7 +53,19 @@ module.exports = store => {
} }
break; break;
case "setEdition": case "setEdition":
localStorage.setItem("edition", payload); if (payload === "custom") {
localStorage.removeItem("edition");
} else {
localStorage.setItem("edition", payload);
localStorage.removeItem("roles");
}
break;
case "setRoles":
if (!payload.length) {
localStorage.removeItem("roles");
} else {
localStorage.setItem("roles", JSON.stringify(payload));
}
break; break;
case "setBluff": case "setBluff":
localStorage.setItem( localStorage.setItem(

View File

@ -9,5 +9,6 @@ $editions:
'tb', 'tb',
'bmr', 'bmr',
'snv', 'snv',
'luf' true 'luf' true,
'custom' true
; ;