Merge pull request #147 from bra1n/fabled

Custom Fabled
This commit is contained in:
Steffen 2021-05-09 21:57:46 +02:00 committed by GitHub
commit 9eb9f44e32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 78 additions and 60 deletions

View File

@ -1,5 +1,10 @@
# Release Notes # Release Notes
### Version 2.13.0
- add support for custom Fabled characters
---
### Version 2.12.0 ### Version 2.12.0
- tweak reference sheet to better fit screen in single column layout - tweak reference sheet to better fit screen in single column layout
- add warning icon overlay for setup roles on character assignment modal - add warning icon overlay for setup roles on character assignment modal

View File

@ -96,7 +96,8 @@ For base game characters, it is sufficient to only provide the ID, similar to wh
- **remindersGlobal**: global reminder tokens that will always be available, no matter if the character is assigned to a player or not - **remindersGlobal**: global reminder tokens that will always be available, no matter if the character is assigned to a player or not
- **setup**: whether this token affects setup (orange leaf), like the Drunk or Baron - **setup**: whether this token affects setup (orange leaf), like the Drunk or Baron
- **name**: the displayed name of this character - **name**: the displayed name of this character
- **team**: the team of the character, has to be one of `townsfolk`, `outsider`, `minion`, `demon` or `traveler` - **team**: the team of the character, has to be one of `townsfolk`, `outsider`, `minion`, `demon`, `traveler` or `fabled`<br>
_Note_: if you create a custom Fabled character, it will be automatically added to the game when the custom script is loaded
- **ability**: the displayed ability text of the character - **ability**: the displayed ability text of the character
## [Code of Conduct](CODE_OF_CONDUCT.md) ## [Code of Conduct](CODE_OF_CONDUCT.md)

16
package-lock.json generated
View File

@ -1,11 +1,11 @@
{ {
"name": "townsquare", "name": "townsquare",
"version": "2.12.0", "version": "2.13.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"version": "2.12.0", "version": "2.13.0",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.32", "@fortawesome/fontawesome-svg-core": "^1.2.32",
@ -1628,9 +1628,9 @@
} }
}, },
"node_modules/cacache/node_modules/ssri": { "node_modules/cacache/node_modules/ssri": {
"version": "6.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz",
"integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==",
"dependencies": { "dependencies": {
"figgy-pudding": "^3.5.1" "figgy-pudding": "^3.5.1"
} }
@ -13477,9 +13477,9 @@
}, },
"dependencies": { "dependencies": {
"ssri": { "ssri": {
"version": "6.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz",
"integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==",
"requires": { "requires": {
"figgy-pudding": "^3.5.1" "figgy-pudding": "^3.5.1"
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "townsquare", "name": "townsquare",
"version": "2.12.0", "version": "2.13.0",
"description": "Blood on the Clocktower Town Square", "description": "Blood on the Clocktower Town Square",
"author": "Steffen Baumgart", "author": "Steffen Baumgart",
"scripts": { "scripts": {

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

View File

@ -162,8 +162,7 @@ export default new Vuex.Store({
* @param roles Array of role IDs or full role definitions * @param roles Array of role IDs or full role definitions
*/ */
setCustomRoles(state, roles) { setCustomRoles(state, roles) {
state.roles = new Map( const processedRoles = roles
roles
// replace numerical role object keys with matching key names // replace numerical role object keys with matching key names
.map(role => { .map(role => {
if (role[0]) { if (role[0]) {
@ -199,17 +198,26 @@ export default new Vuex.Store({
townsfolk: "good", townsfolk: "good",
outsider: "outsider", outsider: "outsider",
minion: "minion", minion: "minion",
demon: "evil" demon: "evil",
fabled: "fabled"
}[role.team] || "custom"; }[role.team] || "custom";
return role; return role;
}) })
// filter out roles that don't match an existing role and also don't have name/ability/team // filter out roles that don't match an existing role and also don't have name/ability/team
.filter(role => role.name && role.ability && role.team) .filter(role => role.name && role.ability && role.team)
// sort by team // sort by team
.sort((a, b) => b.team.localeCompare(a.team)) .sort((a, b) => b.team.localeCompare(a.team));
// convert to Map // convert to Map without Fabled
state.roles = new Map(
processedRoles
.filter(role => role.team !== "fabled")
.map(role => [role.id, role]) .map(role => [role.id, role])
); );
// update Fabled to include custom Fabled from this script
state.fabled = new Map([
...processedRoles.filter(r => r.team === "fabled").map(r => [r.id, r]),
...fabledJSON.map(role => [role.id, role])
]);
// update extraTravelers map to only show travelers not in this script // update extraTravelers map to only show travelers not in this script
state.otherTravelers = new Map( state.otherTravelers = new Map(
rolesJSON rolesJSON

View File

@ -39,8 +39,8 @@ module.exports = store => {
} }
if (localStorage.fabled !== undefined) { if (localStorage.fabled !== undefined) {
store.commit("players/setFabled", { store.commit("players/setFabled", {
fabled: JSON.parse(localStorage.fabled).map(id => fabled: JSON.parse(localStorage.fabled).map(
store.state.fabled.get(id) fabled => store.state.fabled.get(fabled.id) || fabled
) )
}); });
} }
@ -127,7 +127,11 @@ module.exports = store => {
case "players/setFabled": case "players/setFabled":
localStorage.setItem( localStorage.setItem(
"fabled", "fabled",
JSON.stringify(state.players.fabled.map(({ id }) => id)) JSON.stringify(
state.players.fabled.map(fabled =>
fabled.isCustom ? fabled : { id: fabled.id }
)
)
); );
break; break;
case "players/add": case "players/add":

View File

@ -272,7 +272,7 @@ class LiveSession {
votingSpeed: session.votingSpeed, votingSpeed: session.votingSpeed,
lockedVote: session.lockedVote, lockedVote: session.lockedVote,
isVoteInProgress: session.isVoteInProgress, isVoteInProgress: session.isVoteInProgress,
fabled: fabled.map(({ id }) => id), fabled: fabled.map(f => (f.isCustom ? f : { id: f.id })),
...(session.nomination ? { votes: session.votes } : {}) ...(session.nomination ? { votes: session.votes } : {})
}); });
} }
@ -348,7 +348,7 @@ class LiveSession {
isVoteInProgress isVoteInProgress
}); });
this._store.commit("players/setFabled", { 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.id) || f)
}); });
} }
} }
@ -407,7 +407,7 @@ class LiveSession {
const { fabled } = this._store.state.players; const { fabled } = this._store.state.players;
this._send( this._send(
"fabled", "fabled",
fabled.map(({ id }) => id) fabled.map(f => (f.isCustom ? f : { id: f.id }))
); );
} }
@ -419,7 +419,7 @@ class LiveSession {
_updateFabled(fabled) { _updateFabled(fabled) {
if (!this._isSpectator) return; if (!this._isSpectator) return;
this._store.commit("players/setFabled", { 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.id) || f)
}); });
} }