mirror of https://github.com/bra1n/townsquare.git
commit
9eb9f44e32
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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": {
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 136 KiB |
|
@ -162,54 +162,62 @@ 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]) {
|
const customKeys = Object.keys(customRole);
|
||||||
const customKeys = Object.keys(customRole);
|
const mappedRole = {};
|
||||||
const mappedRole = {};
|
for (let prop in role) {
|
||||||
for (let prop in role) {
|
if (customKeys[prop]) {
|
||||||
if (customKeys[prop]) {
|
mappedRole[customKeys[prop]] = role[prop];
|
||||||
mappedRole[customKeys[prop]] = role[prop];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return mappedRole;
|
|
||||||
} else {
|
|
||||||
return role;
|
|
||||||
}
|
}
|
||||||
})
|
return mappedRole;
|
||||||
// clean up role.id
|
} else {
|
||||||
.map(role => {
|
|
||||||
role.id = role.id.toLocaleLowerCase().replace(/[^a-z0-9]/g, "");
|
|
||||||
return role;
|
return role;
|
||||||
})
|
}
|
||||||
// map existing roles to base definition or pre-populate custom roles to ensure all properties
|
})
|
||||||
.map(
|
// clean up role.id
|
||||||
role =>
|
.map(role => {
|
||||||
rolesJSONbyId.get(role.id) ||
|
role.id = role.id.toLocaleLowerCase().replace(/[^a-z0-9]/g, "");
|
||||||
state.roles.get(role.id) ||
|
return role;
|
||||||
Object.assign({}, customRole, role)
|
})
|
||||||
)
|
// map existing roles to base definition or pre-populate custom roles to ensure all properties
|
||||||
// default empty icons and placeholders
|
.map(
|
||||||
.map(role => {
|
role =>
|
||||||
if (rolesJSONbyId.get(role.id)) return role;
|
rolesJSONbyId.get(role.id) ||
|
||||||
role.imageAlt = // map team to generic icon
|
state.roles.get(role.id) ||
|
||||||
{
|
Object.assign({}, customRole, role)
|
||||||
townsfolk: "good",
|
)
|
||||||
outsider: "outsider",
|
// default empty icons and placeholders
|
||||||
minion: "minion",
|
.map(role => {
|
||||||
demon: "evil"
|
if (rolesJSONbyId.get(role.id)) return role;
|
||||||
}[role.team] || "custom";
|
role.imageAlt = // map team to generic icon
|
||||||
return role;
|
{
|
||||||
})
|
townsfolk: "good",
|
||||||
// filter out roles that don't match an existing role and also don't have name/ability/team
|
outsider: "outsider",
|
||||||
.filter(role => role.name && role.ability && role.team)
|
minion: "minion",
|
||||||
// sort by team
|
demon: "evil",
|
||||||
.sort((a, b) => b.team.localeCompare(a.team))
|
fabled: "fabled"
|
||||||
// convert to Map
|
}[role.team] || "custom";
|
||||||
|
return role;
|
||||||
|
})
|
||||||
|
// 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)
|
||||||
|
// sort by team
|
||||||
|
.sort((a, b) => b.team.localeCompare(a.team));
|
||||||
|
// 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
|
||||||
|
|
|
@ -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":
|
||||||
|
|
|
@ -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)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue