2020-05-02 19:11:20 +00:00
|
|
|
import Vue from "vue";
|
|
|
|
import Vuex from "vuex";
|
2020-05-02 19:46:51 +00:00
|
|
|
import persistence from "./persistence";
|
2020-05-30 20:47:42 +00:00
|
|
|
import socket from "./socket";
|
2020-05-02 20:23:05 +00:00
|
|
|
import players from "./modules/players";
|
2020-05-30 20:47:42 +00:00
|
|
|
import session from "./modules/session";
|
2020-05-02 19:11:20 +00:00
|
|
|
import editionJSON from "../editions.json";
|
|
|
|
import rolesJSON from "../roles.json";
|
2020-07-23 11:52:53 +00:00
|
|
|
import fabledJSON from "../fabled.json";
|
2020-05-02 19:11:20 +00:00
|
|
|
|
|
|
|
Vue.use(Vuex);
|
|
|
|
|
2021-02-01 21:33:59 +00:00
|
|
|
// global data maps
|
2020-12-19 21:15:42 +00:00
|
|
|
const editionJSONbyId = new Map(
|
|
|
|
editionJSON.map(edition => [edition.id, edition])
|
|
|
|
);
|
2020-06-24 12:32:08 +00:00
|
|
|
const rolesJSONbyId = new Map(rolesJSON.map(role => [role.id, role]));
|
2020-07-23 11:52:53 +00:00
|
|
|
const fabled = new Map(fabledJSON.map(role => [role.id, role]));
|
2020-06-24 12:32:08 +00:00
|
|
|
|
2021-02-01 21:33:59 +00:00
|
|
|
// helper functions
|
2020-12-19 21:15:42 +00:00
|
|
|
const getRolesByEdition = (edition = editionJSON[0]) => {
|
2020-05-02 19:11:20 +00:00
|
|
|
return new Map(
|
|
|
|
rolesJSON
|
2020-12-19 21:15:42 +00:00
|
|
|
.filter(r => r.edition === edition.id || edition.roles.includes(r.id))
|
2020-05-02 19:11:20 +00:00
|
|
|
.sort((a, b) => b.team.localeCompare(a.team))
|
|
|
|
.map(role => [role.id, role])
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2021-01-25 14:46:37 +00:00
|
|
|
const getTravelersNotInEdition = (edition = editionJSON[0]) => {
|
2021-01-08 17:55:46 +00:00
|
|
|
return new Map(
|
|
|
|
rolesJSON
|
2021-01-09 20:40:59 +00:00
|
|
|
.filter(
|
|
|
|
r =>
|
|
|
|
r.team === "traveler" &&
|
|
|
|
r.edition !== edition.id &&
|
|
|
|
!edition.roles.includes(r.id)
|
|
|
|
)
|
2021-01-08 17:55:46 +00:00
|
|
|
.map(role => [role.id, role])
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2021-02-01 21:33:59 +00:00
|
|
|
const set = key => ({ grimoire }, val) => {
|
|
|
|
grimoire[key] = val;
|
|
|
|
};
|
|
|
|
|
|
|
|
const toggle = key => ({ grimoire }, val) => {
|
|
|
|
if (val === true || val === false) {
|
|
|
|
grimoire[key] = val;
|
|
|
|
} else {
|
|
|
|
grimoire[key] = !grimoire[key];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-07-23 10:25:51 +00:00
|
|
|
// base definition for custom roles
|
|
|
|
const customRole = {
|
2021-02-04 20:40:59 +00:00
|
|
|
id: "",
|
|
|
|
name: "",
|
2020-07-23 10:25:51 +00:00
|
|
|
image: "",
|
2021-02-04 20:40:59 +00:00
|
|
|
ability: "",
|
2020-07-23 10:25:51 +00:00
|
|
|
edition: "custom",
|
|
|
|
firstNight: 0,
|
|
|
|
firstNightReminder: "",
|
|
|
|
otherNight: 0,
|
|
|
|
otherNightReminder: "",
|
|
|
|
reminders: [],
|
|
|
|
remindersGlobal: [],
|
|
|
|
setup: false,
|
|
|
|
team: "townsfolk",
|
|
|
|
isCustom: true
|
|
|
|
};
|
|
|
|
|
2020-05-02 19:11:20 +00:00
|
|
|
export default new Vuex.Store({
|
2020-05-02 20:23:05 +00:00
|
|
|
modules: {
|
2020-05-30 20:47:42 +00:00
|
|
|
players,
|
|
|
|
session
|
2020-05-02 20:23:05 +00:00
|
|
|
},
|
2020-05-02 19:11:20 +00:00
|
|
|
state: {
|
|
|
|
grimoire: {
|
2020-12-02 19:39:12 +00:00
|
|
|
isNight: false,
|
2020-05-02 19:11:20 +00:00
|
|
|
isNightOrder: true,
|
|
|
|
isPublic: true,
|
2020-05-02 19:33:44 +00:00
|
|
|
isMenuOpen: false,
|
2020-12-27 19:49:29 +00:00
|
|
|
isMuted: false,
|
2021-02-01 21:33:59 +00:00
|
|
|
isImageOptIn: false,
|
2020-06-08 10:35:13 +00:00
|
|
|
zoom: 0,
|
2020-11-29 21:17:02 +00:00
|
|
|
background: ""
|
2020-05-12 17:59:48 +00:00
|
|
|
},
|
2020-05-02 19:11:20 +00:00
|
|
|
modals: {
|
|
|
|
edition: false,
|
2020-08-09 19:28:38 +00:00
|
|
|
fabled: false,
|
2020-12-12 21:03:36 +00:00
|
|
|
gameState: false,
|
2020-08-09 19:28:38 +00:00
|
|
|
nightOrder: false,
|
|
|
|
reference: false,
|
2020-07-01 08:44:12 +00:00
|
|
|
reminder: false,
|
2020-08-09 19:28:38 +00:00
|
|
|
role: false,
|
2020-12-06 21:27:52 +00:00
|
|
|
roles: false,
|
|
|
|
voteHistory: false
|
2020-05-02 19:11:20 +00:00
|
|
|
},
|
2020-12-19 21:15:42 +00:00
|
|
|
edition: editionJSONbyId.get("tb"),
|
2020-07-23 11:52:53 +00:00
|
|
|
roles: getRolesByEdition(),
|
2021-01-25 14:49:37 +00:00
|
|
|
otherTravelers: getTravelersNotInEdition(),
|
2020-07-23 11:52:53 +00:00
|
|
|
fabled
|
2020-05-02 19:11:20 +00:00
|
|
|
},
|
2020-07-23 10:25:51 +00:00
|
|
|
getters: {
|
|
|
|
/**
|
2021-02-03 21:12:38 +00:00
|
|
|
* Return all custom roles, with default values and non-essential data stripped.
|
2021-02-04 20:55:04 +00:00
|
|
|
* Role object keys will be replaced with a numerical index to conserve bandwidth.
|
2020-07-23 10:25:51 +00:00
|
|
|
* @param roles
|
|
|
|
* @returns {[]}
|
|
|
|
*/
|
2021-02-03 21:12:38 +00:00
|
|
|
customRolesStripped: ({ roles }) => {
|
2020-07-23 10:25:51 +00:00
|
|
|
const customRoles = [];
|
2021-02-04 20:55:04 +00:00
|
|
|
const customKeys = Object.keys(customRole);
|
2021-02-04 20:40:59 +00:00
|
|
|
const strippedProps = [
|
|
|
|
"firstNightReminder",
|
|
|
|
"otherNightReminder",
|
|
|
|
"isCustom"
|
|
|
|
];
|
2020-07-23 10:25:51 +00:00
|
|
|
roles.forEach(role => {
|
|
|
|
if (!role.isCustom) {
|
|
|
|
customRoles.push({ id: role.id });
|
|
|
|
} else {
|
|
|
|
const strippedRole = {};
|
|
|
|
for (let prop in role) {
|
2021-02-03 21:12:38 +00:00
|
|
|
if (strippedProps.includes(prop)) {
|
2020-07-23 10:25:51 +00:00
|
|
|
continue;
|
|
|
|
}
|
2021-02-03 21:12:38 +00:00
|
|
|
const value = role[prop];
|
2021-02-04 20:55:04 +00:00
|
|
|
if (customKeys.includes(prop) && value !== customRole[prop]) {
|
|
|
|
strippedRole[customKeys.indexOf(prop)] = value;
|
2020-07-23 10:25:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
customRoles.push(strippedRole);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return customRoles;
|
2020-12-23 20:18:35 +00:00
|
|
|
},
|
|
|
|
rolesJSONbyId: () => rolesJSONbyId
|
2020-07-23 10:25:51 +00:00
|
|
|
},
|
2020-05-02 19:11:20 +00:00
|
|
|
mutations: {
|
2021-02-01 21:33:59 +00:00
|
|
|
setZoom: set("zoom"),
|
|
|
|
setBackground: set("background"),
|
|
|
|
toggleMuted: toggle("isMuted"),
|
|
|
|
toggleMenu: toggle("isMenuOpen"),
|
|
|
|
toggleNightOrder: toggle("isNightOrder"),
|
|
|
|
toggleNight: toggle("isNight"),
|
|
|
|
toggleGrimoire: toggle("isPublic"),
|
|
|
|
toggleImageOptIn: toggle("isImageOptIn"),
|
2020-05-02 19:11:20 +00:00
|
|
|
toggleModal({ modals }, name) {
|
2020-06-04 19:56:07 +00:00
|
|
|
if (name) {
|
|
|
|
modals[name] = !modals[name];
|
|
|
|
}
|
|
|
|
for (let modal in modals) {
|
|
|
|
if (modal === name) continue;
|
|
|
|
modals[modal] = false;
|
2020-05-27 19:42:09 +00:00
|
|
|
}
|
2020-05-02 19:11:20 +00:00
|
|
|
},
|
2020-06-30 11:50:35 +00:00
|
|
|
/**
|
|
|
|
* Store custom roles
|
|
|
|
* @param state
|
|
|
|
* @param roles Array of role IDs or full role definitions
|
|
|
|
*/
|
|
|
|
setCustomRoles(state, roles) {
|
2020-05-15 21:36:45 +00:00
|
|
|
state.roles = new Map(
|
2020-06-30 11:50:35 +00:00
|
|
|
roles
|
2021-02-04 20:55:04 +00:00
|
|
|
// replace numerical role object keys with matching key names
|
|
|
|
.map(role => {
|
|
|
|
if (role[0]) {
|
|
|
|
const customKeys = Object.keys(customRole);
|
|
|
|
const mappedRole = {};
|
|
|
|
for (let prop in role) {
|
|
|
|
if (customKeys[prop]) {
|
|
|
|
mappedRole[customKeys[prop]] = role[prop];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return mappedRole;
|
|
|
|
} else {
|
|
|
|
return role;
|
|
|
|
}
|
|
|
|
})
|
2021-03-14 19:42:39 +00:00
|
|
|
// clean up role.id
|
|
|
|
.map(role => {
|
|
|
|
role.id = role.id.toLocaleLowerCase().replace(/[^a-z0-9]/g, "");
|
|
|
|
return role;
|
|
|
|
})
|
2020-06-30 11:50:35 +00:00
|
|
|
// map existing roles to base definition or pre-populate custom roles to ensure all properties
|
|
|
|
.map(
|
|
|
|
role =>
|
2020-12-10 21:30:34 +00:00
|
|
|
rolesJSONbyId.get(role.id) ||
|
|
|
|
state.roles.get(role.id) ||
|
|
|
|
Object.assign({}, customRole, role)
|
2020-06-30 11:50:35 +00:00
|
|
|
)
|
2021-02-04 20:40:59 +00:00
|
|
|
// default empty icons and placeholders
|
2020-07-01 08:20:56 +00:00
|
|
|
.map(role => {
|
2020-07-03 19:28:42 +00:00
|
|
|
if (rolesJSONbyId.get(role.id)) return role;
|
2021-02-04 20:40:59 +00:00
|
|
|
role.imageAlt = // map team to generic icon
|
|
|
|
{
|
|
|
|
townsfolk: "good",
|
|
|
|
outsider: "outsider",
|
|
|
|
minion: "minion",
|
|
|
|
demon: "evil"
|
|
|
|
}[role.team] || "custom";
|
2020-07-01 08:20:56 +00:00
|
|
|
return role;
|
|
|
|
})
|
2020-06-30 11:50:35 +00:00
|
|
|
// 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
|
2020-07-01 08:20:56 +00:00
|
|
|
.sort((a, b) => b.team.localeCompare(a.team))
|
2020-06-30 11:50:35 +00:00
|
|
|
// convert to Map
|
|
|
|
.map(role => [role.id, role])
|
2020-05-15 21:36:45 +00:00
|
|
|
);
|
2021-01-25 15:53:35 +00:00
|
|
|
// update extraTravelers map to only show travelers not in this script
|
2021-01-25 14:49:37 +00:00
|
|
|
state.otherTravelers = new Map(
|
2021-01-15 16:33:33 +00:00
|
|
|
rolesJSON
|
|
|
|
.filter(r => r.team === "traveler" && !roles.some(i => i.id === r.id))
|
|
|
|
.map(role => [role.id, role])
|
|
|
|
);
|
2020-05-15 21:36:45 +00:00
|
|
|
},
|
2020-05-02 19:11:20 +00:00
|
|
|
setEdition(state, edition) {
|
2020-12-19 21:15:42 +00:00
|
|
|
if (editionJSONbyId.has(edition.id)) {
|
|
|
|
state.edition = editionJSONbyId.get(edition.id);
|
|
|
|
state.roles = getRolesByEdition(state.edition);
|
2021-01-25 14:49:37 +00:00
|
|
|
state.otherTravelers = getTravelersNotInEdition(state.edition);
|
2020-12-19 21:15:42 +00:00
|
|
|
} else {
|
|
|
|
state.edition = edition;
|
2020-05-15 21:36:45 +00:00
|
|
|
}
|
2020-12-19 21:15:42 +00:00
|
|
|
state.modals.edition = false;
|
2020-05-02 19:11:20 +00:00
|
|
|
}
|
2020-05-02 19:46:51 +00:00
|
|
|
},
|
2020-05-30 20:47:42 +00:00
|
|
|
plugins: [persistence, socket]
|
2020-05-02 19:11:20 +00:00
|
|
|
});
|