Added some translations stuff.

Better migration check and now triggering.
Minors refactors.
This commit is contained in:
Vlyan
2025-02-16 17:52:15 +01:00
parent 4b6a60d7d6
commit f49919b588
44 changed files with 1412 additions and 1357 deletions

View File

@@ -24,131 +24,131 @@ export const L5R5E = {
mass_battle: "command",
},
noHonorSkillsList: ["commerce", "skulduggery", "medicine", "seafaring", "survival", "labor"],
source_reference: {
sourceReference: {
"core_rulebook": {
value: "core_rulebook",
label: "l5r5e.source_reference.core_rulebook",
type: "Rules"
type: "l5r5e.multiselect.sources_categories.rules"
},
"emerald_empire": {
value: "emerald_empire",
label: "l5r5e.source_reference.emerald_empire",
type: "Rules"
type: "l5r5e.multiselect.sources_categories.rules"
},
"shadowlands": {
value: "shadowlands",
label: "l5r5e.source_reference.shadowlands",
type: "Rules"
type: "l5r5e.multiselect.sources_categories.rules"
},
"court_of_stones": {
value: "court_of_stones",
label: "l5r5e.source_reference.court_of_stones",
type: "Rules"
type: "l5r5e.multiselect.sources_categories.rules"
},
"path_of_waves": {
value: "path_of_waves",
label: "l5r5e.source_reference.path_of_waves",
type: "Rules"
type: "l5r5e.multiselect.sources_categories.rules"
},
"celestial_realms": {
value: "celestial_realms",
label: "l5r5e.source_reference.celestial_realms",
type: "Rules"
type: "l5r5e.multiselect.sources_categories.rules"
},
"fields_of_victory": {
value: "fields_of_victory",
label: "l5r5e.source_reference.fields_of_victory",
type: "Rules"
type: "l5r5e.multiselect.sources_categories.rules"
},
"writ_of_the_wild": {
value: "writ_of_the_wild",
label: "l5r5e.source_reference.writ_of_the_wild",
type: "Rules"
type: "l5r5e.multiselect.sources_categories.rules"
},
"gm_kit": {
value: "gm_kit",
label: "l5r5e.source_reference.gm_kit",
type: "Rules"
type: "l5r5e.multiselect.sources_categories.rules"
},
"beginner_game": {
value: "beginner_game",
label: "l5r5e.source_reference.beginner_game",
type: "Rules"
type: "l5r5e.multiselect.sources_categories.rules"
},
"the_mantis_clan": {
value: "the_mantis_clan",
label: "l5r5e.source_reference.the_mantis_clan",
type: "Supplement"
type: "l5r5e.multiselect.sources_categories.supplements"
},
"legacies_of_war": {
value: "legacies_of_war",
label: "l5r5e.source_reference.legacies_of_war",
type: "Supplement"
type: "l5r5e.multiselect.sources_categories.supplements"
},
"mask_of_the_oni": {
value: "mask_of_the_oni",
label: "l5r5e.source_reference.mask_of_the_oni",
type: "Adventure"
type: "l5r5e.multiselect.sources_categories.adventures"
},
"winters_embrace": {
value: "winters_embrace",
label: "l5r5e.source_reference.winters_embrace",
type: "Adventure"
type: "l5r5e.multiselect.sources_categories.adventures"
},
"sins_of_regret": {
value: "sins_of_regret",
label: "l5r5e.source_reference.sins_of_regret",
type: "Adventure"
type: "l5r5e.multiselect.sources_categories.adventures"
},
"wheele_of_judgment": {
value: "wheele_of_judgment",
label: "l5r5e.source_reference.wheele_of_judgment",
type: "Adventure"
"wheel_of_judgment": {
value: "wheel_of_judgment",
label: "l5r5e.source_reference.wheel_of_judgment",
type: "l5r5e.multiselect.sources_categories.adventures"
},
"blood_of_the_lioness": {
value: "blood_of_the_lioness",
label: "l5r5e.source_reference.blood_of_the_lioness",
type: "Adventure"
type: "l5r5e.multiselect.sources_categories.adventures"
},
"imperfect_land": {
value: "imperfect_land",
label: "l5r5e.source_reference.imperfect_land",
type: "Adventure"
type: "l5r5e.multiselect.sources_categories.adventures"
},
"in_the_palace_of_the_emerald_champion": {
value: "in_the_palace_of_the_emerald_champion",
label: "l5r5e.source_reference.in_the_palace_of_the_emerald_champion",
type: "Adventure"
type: "l5r5e.multiselect.sources_categories.adventures"
},
"the_highwayman": {
value: "the_highwayman",
label: "l5r5e.source_reference.the_highwayman",
type: "Adventure"
type: "l5r5e.multiselect.sources_categories.adventures"
},
"wedding_at_kyotei_castle": {
value: "wedding_at_kyotei_castle",
label: "l5r5e.source_reference.wedding_at_kyotei_castle",
type: "Adventure"
type: "l5r5e.multiselect.sources_categories.adventures"
},
"the_knotted_tails": {
value: "the_knotted_tails",
label: "l5r5e.source_reference.the_knotted_tails",
type: "Adventure"
type: "l5r5e.multiselect.sources_categories.adventures"
},
"cresting_waves": {
value: "cresting_waves",
label: "l5r5e.source_reference.cresting_waves",
type: "Adventure"
type: "l5r5e.multiselect.sources_categories.adventures"
},
"deathly_turns": {
value: "deathly_turns",
label: "l5r5e.source_reference.deathly_turns",
type: "Adventure"
type: "l5r5e.multiselect.sources_categories.adventures"
},
"the_scroll_or_the_blade": {
value: "the_scroll_or_the_blade",
label: "l5r5e.source_reference.the_scroll_or_the_blade",
type: "Adventure"
type: "l5r5e.multiselect.sources_categories.adventures"
},
},
};

View File

@@ -1,9 +1,9 @@
import { HTML_l5r5e_MultiSelectElement } from "../misc/l5r5e-multiselect.js";
import { L5r5eHtmlMultiSelectElement } from "../misc/l5r5e-multiselect.js";
/**
* A subclass of [ArrayField]{@link ArrayField} which supports a set of contained elements.
* Elements in this set are treated as fungible and may be represented in any order or discarded if invalid.
*/
export class l5r5e_SetField extends foundry.data.fields.SetField {
export class L5r5eSetField extends foundry.data.fields.SetField {
// We don't get the options we expect when we convert this to input,
// So store them here
@@ -13,30 +13,30 @@ export class l5r5e_SetField extends foundry.data.fields.SetField {
super(new foundry.data.fields.StringField({
choices: options.options.map((option) => option.value)
}), options, context);
this.#savedOptions = options;
}
/** @override */
initialize(value, model, options={}) {
if ( !value ) return value;
return new Set(super.initialize(value, model, options));
}
/** @override */
toObject(value) {
if ( !value ) return value;
return Array.from(value).map(v => this.element.toObject(v));
}
/* -------------------------------------------- */
/* Form Field Integration */
/* -------------------------------------------- */
/** @override */
_toInput(config) {
const e = this.element;
return HTML_l5r5e_MultiSelectElement.create({
return L5r5eHtmlMultiSelectElement.create({
name: config.name,
options: this.#savedOptions.options,
groups: this.#savedOptions.groups,

View File

@@ -1,4 +1,4 @@
import { HTML_l5r5e_MultiSelectElement } from "./misc/l5r5e-multiselect.js";
import { L5r5eHtmlMultiSelectElement } from "./misc/l5r5e-multiselect.js";
export default class HooksL5r5e {
/**
@@ -59,14 +59,16 @@ export default class HooksL5r5e {
}
// Find all additional source references that is not the official ones:
const references = new Set(Object.keys(CONFIG.l5r5e.source_reference));
const references = new Set(Object.keys(CONFIG.l5r5e.sourceReference));
for(let pack of game.packs) {
if(pack.metadata.packageType === "system")
if(pack.metadata.packageType === "system") {
continue;
}
const documents = await pack.getDocuments();
for(let document of documents) {
if(document?.system?.source_reference)
if(document?.system?.source_reference) {
references.add(document.system.source_reference.source);
}
}
}
game.settings.set(CONFIG.l5r5e.namespace, "all-compendium-references", Array.from(references));
@@ -228,7 +230,7 @@ export default class HooksL5r5e {
*/
static async renderCompendium(app, html, data) {
if (app.collection.documentName === "Item") {
const content = await app.collection.getDocuments();
const content = await app.collection.getDocuments();
let sources_in_this_compendium = new Set([]);
let filters_to_show = {
rank: false,
@@ -239,7 +241,7 @@ export default class HooksL5r5e {
// Add additional data to the entries to make it faster to lookup.
// Add Ring/rank/rarity information
content.forEach(async (document) => {
for (const document of content) {
const entry = html.find(`[data-document-id="${document.id}"]`);
if(document.system?.rank) {
entry.data("rank", document.system.rank);
@@ -267,17 +269,16 @@ export default class HooksL5r5e {
const ring_rarity_rank = await renderTemplate(`${CONFIG.l5r5e.paths.templates}compendium/ring-rarity-rank.html`, document.system);
entry.append(ring_rarity_rank);
}
});
}
//Setup what the player cannot see.
const officialcontent = game.settings.get(CONFIG.l5r5e.namespace, "compendium-official-content-for-players");
const inofficialcontent = game.settings.get(CONFIG.l5r5e.namespace, "compendium-inofficial-content-for-players");
let sources_to_mark_as_innaccessable_to_players = game.settings.get(CONFIG.l5r5e.namespace, "all-compendium-references")
const officialContent = game.settings.get(CONFIG.l5r5e.namespace, "compendium-official-content-for-players");
const unofficialContent = game.settings.get(CONFIG.l5r5e.namespace, "compendium-unofficial-content-for-players");
const unavailableSourceForPlayers = game.settings.get(CONFIG.l5r5e.namespace, "all-compendium-references")
.filter((element) => {
if(CONFIG.l5r5e.source_reference[element])
return !officialcontent.includes(element);
else
return inofficialcontent.includes(element);
return CONFIG.l5r5e.sourceReference[element]
? !officialContent.includes(element)
: unofficialContent.includes(element);
});
// Create the function that will hide/show elements based on various factors
@@ -287,13 +288,15 @@ export default class HooksL5r5e {
const user_filter = header.find("l5r5e-multi-select").val();
const ring_filter = header.find(".ring-filter").find(".selected").data("ring");
const rarity_filter = header.find(".rarity-filter").find(".selected").data("rarity");
$(html).find(".directory-item").each(function() {
const lineSource = $(this).data("source")?.source;
if(lineSource === null || lineSource === undefined)
if(lineSource === null || lineSource === undefined) {
return; // We might have stuff in the compendium view that does not have a source (folders etc.) Ignore those.
}
let should_show = true;
if(sources_to_mark_as_innaccessable_to_players.includes(lineSource)) {
if(unavailableSourceForPlayers.includes(lineSource)) {
if(game.user.isGM) {
should_show &= true;
$(this).addClass("not-for-players");
@@ -331,10 +334,11 @@ export default class HooksL5r5e {
should_show &= $(this).data("rarity") == rarity_filter
}
if(should_show)
if(should_show) {
$(this).show();
else
} else {
$(this).hide();
}
});
}
@@ -410,8 +414,8 @@ export default class HooksL5r5e {
if(filters_to_show.source) {
// Setup the source select and add it to the document with change callback
const selectable_sources = game.settings.get(CONFIG.l5r5e.namespace, "all-compendium-references")
.map((reference) => {
return {
.map((reference) => {
return {
disable: !sources_in_this_compendium.has(reference),
source: reference
}
@@ -419,14 +423,14 @@ export default class HooksL5r5e {
.map((reference) => {
return {
value: reference.source,
label: CONFIG.l5r5e.source_reference[reference.source]?.label ?? reference.source,
label: CONFIG.l5r5e.sourceReference[reference.source]?.label ?? reference.source,
translate: true,
group: CONFIG.l5r5e.source_reference[reference.source]?.type.split(",")[0] ?? "Other",
group: CONFIG.l5r5e.sourceReference[reference.source]?.type.split(",")[0] ?? "l5r5e.multiselect.sources_categories.others",
disabled: reference.disable
}
});
const filterSourcesBox = HTML_l5r5e_MultiSelectElement.create({
const filterSourcesBox = L5r5eHtmlMultiSelectElement.create({
name: "filter-sources",
options: selectable_sources,
localize: true,
@@ -438,10 +442,13 @@ export default class HooksL5r5e {
// If gm add a extra button to easily filter the content to see the same stuff as a player
if(game.user.isGM) {
const buttonHTML = '<button type="button" class="gm" data-tooltip="Apply player filter">Player filter</button>'
const buttonHTML = `<button type="button" class="gm" data-tooltip="${game.i18n.localize('l5r5e.multiselect.player_filter_tooltip')}">`
+ game.i18n.localize('l5r5e.multiselect.player_filter_label')
+ '</button>'
$(buttonHTML).appendTo($(header).find("l5r5e-multi-select")).click(function() {
const filter = game.settings.get(CONFIG.l5r5e.namespace, "all-compendium-references").filter((reference) => {
return !sources_to_mark_as_innaccessable_to_players.includes(reference);
return !unavailableSourceForPlayers.includes(reference);
})
header.find("l5r5e-multi-select")[0].value = filter.filter((element) => element !== "");
@@ -449,13 +456,14 @@ export default class HooksL5r5e {
}
}
// TODO find a better way
// This is ugly but if we hide the content too early then it won't be hidden for some reason.
// Current guess is that the foundry search filter is doing something.
// Adding a delay here so that we hide the content. This will fail on slow computers/network...
setTimeout(() => {
applyCompendiumFilter();
}, 250)
return false;
}
}

View File

@@ -52,13 +52,13 @@ export class BaseItemSheetL5r5e extends ItemSheet {
// Translate current reference
const reference = this.item.system.source_reference.source;
const label_or_reference = CONFIG.l5r5e.source_reference[reference]?.label ?? reference
const label_or_reference = CONFIG.l5r5e.sourceReference[reference]?.label ?? reference
sheetData.data.system.source_reference.source = game.i18n.localize(label_or_reference);
// Translate list of available references
const all_references = game.settings.get(CONFIG.l5r5e.namespace, "all-compendium-references");
sheetData.source_references = all_references.map((reference) => {
const label_or_reference = CONFIG.l5r5e.source_reference[reference]?.label ?? reference
const label_or_reference = CONFIG.l5r5e.sourceReference[reference]?.label ?? reference
return game.i18n.localize(label_or_reference)
})
@@ -73,16 +73,15 @@ export class BaseItemSheetL5r5e extends ItemSheet {
* @override
*/
async _updateObject(event, formData) {
// If we have an official source then store the id instead
if(event.currentTarget.name === "system.source_reference.source") {
Object.entries(CONFIG.l5r5e.source_reference).forEach(([id, value]) => {
if(event.currentTarget?.name === "system.source_reference.source") {
Object.entries(CONFIG.l5r5e.sourceReference).forEach(([id, value]) => {
if(game.i18n.localize(value.label) === formData["system.source_reference.source"]) {
formData["system.source_reference.source"] = id;
}
});
}
return super._updateObject(event,formData);
}

View File

@@ -44,9 +44,9 @@ import { GmToolbox } from "./gm/gm-toolbox.js";
import { GmMonitor } from "./gm/gm-monitor.js";
import { Storage } from "./storage.js";
// Misc
import { HTML_l5r5e_MultiSelectElement } from "./misc/l5r5e-multiselect.js";
import { L5r5eHtmlMultiSelectElement } from "./misc/l5r5e-multiselect.js";
window.customElements.define(HTML_l5r5e_MultiSelectElement.tagName, HTML_l5r5e_MultiSelectElement);
window.customElements.define(L5r5eHtmlMultiSelectElement.tagName, L5r5eHtmlMultiSelectElement);
/* ------------------------------------ */
/* Initialize system */

View File

@@ -6,7 +6,7 @@ export class MigrationL5r5e {
* Minimum Version needed for migration stuff to trigger
* @type {string}
*/
static NEEDED_VERSION = "1.3.0";
static NEEDED_VERSION = "1.12.3";
/**
* Return true if the version need some updates
@@ -289,15 +289,21 @@ export class MigrationL5r5e {
// ***** Start of 1.12.3 *****
if (options?.force || MigrationL5r5e.needUpdate("1.12.3")) {
// Splitting book reference & page
if(item.system.book_reference) {
const book_reference = item.system.book_reference.match("(.+) p\.(\\d+)");
if(book_reference === null) {
const bookReference = item.system.book_reference.match(/^((?!p\.)\D+?)?(?:\s*p\.)?(\d+)?$/);
if (!bookReference) {
console.warn(`L5R5E | Migration | Failed to properly migrate item document ${item.name}[${item._id}]: Could not parse the book_reference`);
updateData["system.source_reference.source"] = item.system.book_reference;
return updateData;
} else {
updateData["system.source_reference.source"] = bookReference[1]?.trim();
updateData["system.source_reference.page"] = bookReference[2];
}
updateData["system.source_reference.source"] = book_reference[1].trim();
updateData["system.source_reference.page_nr"] = book_reference[2];
// TODO uncomment before release
// Delete the old key
//updateData["system.-=book_reference"] = null;
}
}
// ***** End of 1.12.3 *****

View File

@@ -20,7 +20,7 @@ const { AbstractMultiSelectElement } = foundry.applications.elements;
* </l5r5e-multi-select>
* ```
*/
export class HTML_l5r5e_MultiSelectElement extends AbstractMultiSelectElement {
export class L5r5eHtmlMultiSelectElement extends AbstractMultiSelectElement {
constructor() {
super();
@@ -56,7 +56,7 @@ export class HTML_l5r5e_MultiSelectElement extends AbstractMultiSelectElement {
/* -------------------------------------------- */
// We will call initalize twice (one in the parent constructor) then one in #setup
// We will call initialize twice (one in the parent constructor) then one in #setup
// required since when we want to build the elements we should to an initialize first
// and we cannot override _initialize since we don't have access to #disabledValues there
#setup() {
@@ -185,7 +185,7 @@ export class HTML_l5r5e_MultiSelectElement extends AbstractMultiSelectElement {
/**
* Create a HTML_l5r5e_MultiSelectElement using provided configuration data.
* @param {FormInputConfig<string[]> & Omit<SelectInputConfig, "blank">} config
* @returns {HTML_l5r5e_MultiSelectElement}
* @returns {L5r5eHtmlMultiSelectElement}
*/
static create(config) {
// Foundry creates either a select with tag multi-select or multi-checkboxes. We want a l5r5e-multi-select
@@ -193,7 +193,7 @@ export class HTML_l5r5e_MultiSelectElement extends AbstractMultiSelectElement {
const groups = prepareSelectOptionGroups(config);
//Setup the HTML
const select = document.createElement(HTML_l5r5e_MultiSelectElement.tagName);
const select = document.createElement(L5r5eHtmlMultiSelectElement.tagName);
select.name = config.name;
foundry.applications.fields.setInputAttributes(select, config);
for (const group_entry of groups) {
@@ -210,7 +210,7 @@ export class HTML_l5r5e_MultiSelectElement extends AbstractMultiSelectElement {
}
/** Stolen from foundry.applications.fields.prepareSelectOptionGroups: Needed to add support for tooltips
*
*
*/
function prepareSelectOptionGroups(config) {
const result = foundry.applications.fields.prepareSelectOptionGroups(config);

View File

@@ -1,4 +1,4 @@
import { l5r5e_SetField } from "./data/l5r5e-setfield.js";
import { L5r5eSetField } from "./data/l5r5e-setfield.js";
/**
* Custom system settings register
@@ -51,25 +51,27 @@ export const RegisterSettings = function () {
/* -------------------------------------- */
/* Compendium view Settings (GM only) */
/* -------------------------------------- */
// This value is updated wheneveer we add a reference and on boot
// This value is updated whenever we add a reference and on boot
game.settings.register(CONFIG.l5r5e.namespace, "all-compendium-references", {
type: new foundry.data.fields.SetField(new foundry.data.fields.StringField()),
default: Object.keys(CONFIG.l5r5e.source_reference),
default: Object.keys(CONFIG.l5r5e.sourceReference),
config: false,
scope: "world",
});
game.settings.register(CONFIG.l5r5e.namespace, "compendium-official-content-for-players", {
name: "SETTINGS.Compendium.AllowedOfficialSources.Title",
hint: "SETTINGS.Compendium.AllowedOfficialSources.Hint",
type: new l5r5e_SetField( {
groups: Array.from(new Set(Object.values(CONFIG.l5r5e.source_reference).map(value => (value.type.split(",")).map(value => value.trim())).flat())).concat("Other"),
options: Object.values(CONFIG.l5r5e.source_reference).map((reference) => {
type: new L5r5eSetField( {
groups: Array.from(new Set(Object.values(CONFIG.l5r5e.sourceReference).map(value =>
(value.type.split(",")).map(value => value.trim())
).flat()))
.concat("l5r5e.multiselect.sources_categories.others"),
options: Object.values(CONFIG.l5r5e.sourceReference).map((reference) => {
return {
...reference,
localize: true,
group: CONFIG.l5r5e.source_reference[reference.value]?.type ?? "Other"
group: CONFIG.l5r5e.sourceReference[reference.value]?.type ?? "l5r5e.multiselect.sources_categories.others"
};
})
}),
@@ -78,9 +80,9 @@ export const RegisterSettings = function () {
scope: "world",
});
game.settings.register(CONFIG.l5r5e.namespace, "compendium-inofficial-content-for-players", {
name: "SETTINGS.Compendium.AllowedInOfficialSources.Title",
hint: "SETTINGS.Compendium.AllowedInOfficialSources.Hint",
game.settings.register(CONFIG.l5r5e.namespace, "compendium-unofficial-content-for-players", {
name: "SETTINGS.Compendium.AllowedUnofficialSources.Title",
hint: "SETTINGS.Compendium.AllowedUnofficialSources.Hint",
type: new foundry.data.fields.SetField(new foundry.data.fields.StringField()),
default: [],
config: true,