COrrections, WIP
This commit is contained in:
@@ -10,6 +10,8 @@ export class AdvancementSheetL5r5e extends ItemSheetL5r5e {
|
||||
static types = [
|
||||
{ id: "ring", label: "l5r5e.rings.label" },
|
||||
{ id: "skill", label: "l5r5e.skills.label" },
|
||||
{ id: "arcane", label: "l5r5e.chiaroscuro.arcane.label" },
|
||||
{ id: "mot_invocation", label: "l5r5e.chiaroscuro.technique.mot_invocation" },
|
||||
// others have theirs own xp count
|
||||
];
|
||||
|
||||
@@ -27,6 +29,12 @@ export class AdvancementSheetL5r5e extends ItemSheetL5r5e {
|
||||
sheetData.data.subTypesList = AdvancementSheetL5r5e.types;
|
||||
sheetData.data.skillsList = game.l5r5e.HelpersL5r5e.getSkillsList(true);
|
||||
|
||||
// Invocation sub-types (Général / Neutre / Précis)
|
||||
const invTypes = game.l5r5e.HelpersL5r5e.getLocalizedRawObject("l5r5e.chiaroscuro.technique.invocation_types") ?? {};
|
||||
sheetData.data.invocationTypesList = [{ id: "", label: "—" }].concat(
|
||||
Object.entries(invTypes).map(([id, label]) => ({ id, label }))
|
||||
);
|
||||
|
||||
return sheetData;
|
||||
}
|
||||
|
||||
@@ -49,15 +57,22 @@ export class AdvancementSheetL5r5e extends ItemSheetL5r5e {
|
||||
html.find("#advancement_type").on("change", (event) => {
|
||||
const targetEvt = $(event.target);
|
||||
targetEvt.prop("disabled", true);
|
||||
const val = targetEvt.val();
|
||||
|
||||
if (targetEvt.val() === "skill") {
|
||||
if (val === "skill") {
|
||||
this._updateChoice({ ring: currentRing }, { skill: currentSkill }).then(
|
||||
targetEvt.prop("disabled", false)
|
||||
);
|
||||
} else if (targetEvt.val() === "ring") {
|
||||
} else if (val === "ring") {
|
||||
this._updateChoice({ skill: currentSkill }, { ring: currentRing }).then(
|
||||
targetEvt.prop("disabled", false)
|
||||
);
|
||||
} else {
|
||||
// arcane or mot_invocation: just save the type, no auto-calc
|
||||
this.object.update({ system: { advancement_type: val } }).then(() => {
|
||||
targetEvt.prop("disabled", false);
|
||||
this.render(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ export class ArcaneSheetL5r5e extends BaseItemSheetL5r5e {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["l5r5e", "sheet", "arcane"],
|
||||
template: CONFIG.l5r5e.paths.templates + "items/arcane/arcane-sheet.html",
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "attributes" }],
|
||||
width: 500,
|
||||
height: 400,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
import { ItemSheetL5r5e } from "./item-sheet.js";
|
||||
|
||||
/**
|
||||
* @extends {ItemSheetL5r5e}
|
||||
*/
|
||||
export class ArmyCohortSheetL5r5e extends ItemSheetL5r5e {
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["l5r5e", "sheet", "army-cohort"],
|
||||
template: CONFIG.l5r5e.paths.templates + "items/army-cohort/army-cohort-sheet.html",
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "infos" }],
|
||||
dragDrop: [{ dragSelector: ".item", dropSelector: null }],
|
||||
});
|
||||
}
|
||||
|
||||
/** @override */
|
||||
constructor(options = {}) {
|
||||
super(options);
|
||||
this._initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize once
|
||||
* @private
|
||||
*/
|
||||
_initialize() {
|
||||
const data = this.object.system;
|
||||
|
||||
// update linked actor datas
|
||||
if (data.leader_actor_id) {
|
||||
const actor = game.actors.get(data.leader_actor_id);
|
||||
if (actor) {
|
||||
this._updateLinkedActorData(actor);
|
||||
} else {
|
||||
this._removeLinkedActor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Object|Promise}
|
||||
*/
|
||||
async getData(options = {}) {
|
||||
const sheetData = await super.getData(options);
|
||||
|
||||
// Editors enrichment
|
||||
sheetData.data.enrichedHtml.abilities = await foundry.applications.ux.TextEditor.implementation.enrichHTML(sheetData.data.system.abilities, {
|
||||
async: true,
|
||||
});
|
||||
|
||||
return sheetData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate a named TinyMCE text editor
|
||||
* @param {string} name The named data field which the editor modifies.
|
||||
* @param {object} options TinyMCE initialization options passed to TextEditor.create
|
||||
* @param {string} initialContent Initial text content for the editor area.
|
||||
* @override
|
||||
*/
|
||||
activateEditor(name, options = {}, initialContent = "") {
|
||||
// Symbols Compatibility with old compendium modules (PRE l5r v1.7.2)
|
||||
if (name === "system.abilities" && initialContent) {
|
||||
initialContent = game.l5r5e.HelpersL5r5e.convertSymbols(initialContent, false);
|
||||
}
|
||||
return super.activateEditor(name, options, initialContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to events from the sheet.
|
||||
* @param {jQuery} html HTML content of the sheet.
|
||||
*/
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// *** Everything below here is only needed if the sheet is editable ***
|
||||
if (!this.isEditable) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete the linked Actor
|
||||
html.find(".actor-remove-control").on("click", (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this._removeLinkedActor();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle dropped Item data on the Actor sheet (cohort, fortification)
|
||||
* @param {DragEvent} event
|
||||
*/
|
||||
async _onDrop(event) {
|
||||
// *** Everything below here is only needed if the sheet is editable ***
|
||||
if (!this.isEditable) {
|
||||
return;
|
||||
}
|
||||
|
||||
const droppedActor = await game.l5r5e.HelpersL5r5e.getDragnDropTargetObject(event);
|
||||
return this._updateLinkedActorData(droppedActor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update actor datas for this army sheet
|
||||
* @param {ActorL5r5e} actor actor object
|
||||
* @return {Promise<abstract.Document>}
|
||||
* @private
|
||||
*/
|
||||
async _updateLinkedActorData(actor) {
|
||||
if (!actor || actor.documentName !== "Actor" || !actor.isCharacterType) {
|
||||
console.warn("L5R5E | Army Cohort | Wrong actor type", actor?.type, actor);
|
||||
return;
|
||||
}
|
||||
|
||||
return this.object.update({
|
||||
img: actor.img,
|
||||
system: {
|
||||
leader: actor.name,
|
||||
leader_actor_id: actor._id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the linked actor (commander/warlord)
|
||||
* @return {Promise<void>}
|
||||
* @private
|
||||
*/
|
||||
async _removeLinkedActor() {
|
||||
return this.object.update({
|
||||
system: {
|
||||
leader_actor_id: null,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { ItemSheetL5r5e } from "./item-sheet.js";
|
||||
|
||||
/**
|
||||
* @extends {ItemSheetL5r5e}
|
||||
*/
|
||||
export class ArmyFortificationSheetL5r5e extends ItemSheetL5r5e {
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["l5r5e", "sheet", "army-fortification"],
|
||||
template: CONFIG.l5r5e.paths.templates + "items/army-fortification/army-fortification-sheet.html",
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { ItemSheetL5r5e } from "./item-sheet.js";
|
||||
|
||||
/**
|
||||
* @extends {ItemSheet}
|
||||
*/
|
||||
export class BondSheetL5r5e extends ItemSheetL5r5e {
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["l5r5e", "sheet", "bond"],
|
||||
template: CONFIG.l5r5e.paths.templates + "items/bond/bond-sheet.html",
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
import { ItemSheetL5r5e } from "./item-sheet.js";
|
||||
|
||||
/**
|
||||
* @extends {ItemSheet}
|
||||
*/
|
||||
export class ItemPatternSheetL5r5e extends ItemSheetL5r5e {
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["l5r5e", "sheet", "item-pattern"],
|
||||
template: CONFIG.l5r5e.paths.templates + "items/item-pattern/item-pattern-sheet.html",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Object|Promise}
|
||||
*/
|
||||
async getData(options = {}) {
|
||||
const sheetData = await super.getData(options);
|
||||
|
||||
// Linked Property
|
||||
sheetData.data.linkedProperty = await this.getLinkedProperty(sheetData);
|
||||
|
||||
return sheetData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the linked property name
|
||||
* @param sheetData
|
||||
* @return {Promise<null|{name, id}>}
|
||||
*/
|
||||
async getLinkedProperty(sheetData) {
|
||||
if (sheetData.data.system.linked_property_id) {
|
||||
const linkedProperty = await game.l5r5e.HelpersL5r5e.getObjectGameOrPack({
|
||||
id: sheetData.data.system.linked_property_id,
|
||||
type: "Item",
|
||||
});
|
||||
if (linkedProperty) {
|
||||
return {
|
||||
id: linkedProperty._id,
|
||||
name: linkedProperty.name,
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to events from the sheet.
|
||||
* @param {jQuery} html HTML content of the sheet.
|
||||
*/
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.isEditable) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete the linked property
|
||||
html.find(`.linked-property-delete`).on("click", this._deleteLinkedProperty.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback actions which occur when a dragged element is dropped on a target.
|
||||
* @param {DragEvent} event The originating DragEvent
|
||||
* @private
|
||||
*/
|
||||
async _onDrop(event) {
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.isEditable) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only property allowed here
|
||||
let item = await game.l5r5e.HelpersL5r5e.getDragnDropTargetObject(event);
|
||||
if (!item || item.documentName !== "Item" || item.type !== "property") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the new property, and update
|
||||
this.document.system.linked_property_id = item.id;
|
||||
this.document.update({
|
||||
system: {
|
||||
linked_property_id: this.document.system.linked_property_id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the link to a property for the current item
|
||||
* @param {Event} event
|
||||
* @return {Promise<void>}
|
||||
* @private
|
||||
*/
|
||||
async _deleteLinkedProperty(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
let name;
|
||||
const linkedProperty = await game.l5r5e.HelpersL5r5e.getObjectGameOrPack({
|
||||
id: this.document.system.linked_property_id,
|
||||
type: "Item",
|
||||
});
|
||||
if (linkedProperty) {
|
||||
name = linkedProperty.name;
|
||||
}
|
||||
|
||||
const callback = async () => {
|
||||
this.document.system.linked_property_id = null;
|
||||
this.document.update({
|
||||
system: {
|
||||
linked_property_id: this.document.system.linked_property_id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// Holing Ctrl = without confirm
|
||||
if (event.ctrlKey || !name) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
game.l5r5e.HelpersL5r5e.confirmDeleteDialog(
|
||||
game.i18n.format("l5r5e.global.delete_confirm", { name }),
|
||||
callback
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -108,19 +108,12 @@ export class ItemSheetL5r5e extends BaseItemSheetL5r5e {
|
||||
}
|
||||
|
||||
// If we are a property, the child id need to be different to parent
|
||||
// (property type removed — guard kept for legacy data safety)
|
||||
if (this.item.type === "property" && this.item.id === item._id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Specific ItemPattern's drop, get the associated props instead
|
||||
if (item.type === "item_pattern" && item.system.linked_property_id) {
|
||||
item = await game.l5r5e.HelpersL5r5e.getObjectGameOrPack({
|
||||
id: item.system.linked_property_id,
|
||||
type: "Item",
|
||||
});
|
||||
}
|
||||
|
||||
// Final object has to be a property
|
||||
// Final object has to be a property (type removed — no more drops possible)
|
||||
if (item.type !== "property") {
|
||||
return;
|
||||
}
|
||||
|
||||
59
system/scripts/items/mot-invocation-sheet.js
Normal file
59
system/scripts/items/mot-invocation-sheet.js
Normal file
@@ -0,0 +1,59 @@
|
||||
import { BaseItemSheetL5r5e } from "./base-item-sheet.js";
|
||||
|
||||
/** Mode Invocation values per invocation type */
|
||||
const INVOCATION_MODE = {
|
||||
general: 3,
|
||||
neutre: 0,
|
||||
precis: -3,
|
||||
};
|
||||
|
||||
/**
|
||||
* Sheet for Mot d'Invocation items (Chiaroscuro).
|
||||
* @extends {BaseItemSheetL5r5e}
|
||||
*/
|
||||
export class MotInvocationSheetL5r5e extends BaseItemSheetL5r5e {
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["l5r5e", "sheet", "mot-invocation"],
|
||||
template: CONFIG.l5r5e.paths.templates + "items/mot_invocation/mot-invocation-sheet.html",
|
||||
width: 500,
|
||||
height: 360,
|
||||
});
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async getData(options = {}) {
|
||||
const sheetData = await super.getData(options);
|
||||
|
||||
// Build invocation types list from i18n
|
||||
const invTypes = game.l5r5e.HelpersL5r5e.getLocalizedRawObject("l5r5e.chiaroscuro.technique.invocation_types") ?? {};
|
||||
sheetData.data.invocationTypesList = [{ id: "", label: "—" }].concat(
|
||||
Object.entries(invTypes).map(([id, label]) => ({ id, label }))
|
||||
);
|
||||
|
||||
sheetData.data.enrichedHtml = {
|
||||
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
sheetData.data.system.description ?? "",
|
||||
{ async: true }
|
||||
),
|
||||
};
|
||||
|
||||
return sheetData;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
if (!this.isEditable) return;
|
||||
|
||||
html.find("#mot_invocation_type").on("change", async (event) => {
|
||||
const type = event.target.value;
|
||||
const mode = INVOCATION_MODE[type] ?? 0;
|
||||
// Update stored value and refresh display
|
||||
await this.object.update({ system: { invocation_type: type, mode_invocation: mode } });
|
||||
this.render(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,8 @@ export class MystereSheetL5r5e extends BaseItemSheetL5r5e {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["l5r5e", "sheet", "mystere"],
|
||||
template: CONFIG.l5r5e.paths.templates + "items/mystere/mystere-sheet.html",
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "attributes" }],
|
||||
width: 500,
|
||||
height: 380,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { ItemSheetL5r5e } from "./item-sheet.js";
|
||||
|
||||
/**
|
||||
* @extends {ItemSheet}
|
||||
*/
|
||||
export class PropertySheetL5r5e extends ItemSheetL5r5e {
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["l5r5e", "sheet", "property"],
|
||||
template: CONFIG.l5r5e.paths.templates + "items/property/property-sheet.html",
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { ItemSheetL5r5e } from "./item-sheet.js";
|
||||
|
||||
/**
|
||||
* @extends {ItemSheet}
|
||||
*/
|
||||
export class SignatureScrollSheetL5r5e extends ItemSheetL5r5e {
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["l5r5e", "sheet", "signature-scroll"],
|
||||
template: CONFIG.l5r5e.paths.templates + "items/signature-scroll/signature-scroll-sheet.html",
|
||||
});
|
||||
}
|
||||
}
|
||||
31
system/scripts/items/technique-ecole-sheet.js
Normal file
31
system/scripts/items/technique-ecole-sheet.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { BaseItemSheetL5r5e } from "./base-item-sheet.js";
|
||||
|
||||
/**
|
||||
* Sheet for Technique École items (Chiaroscuro).
|
||||
* @extends {BaseItemSheetL5r5e}
|
||||
*/
|
||||
export class TechniqueEcoleSheetL5r5e extends BaseItemSheetL5r5e {
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["l5r5e", "sheet", "technique-ecole"],
|
||||
template: CONFIG.l5r5e.paths.templates + "items/technique_ecole/technique-ecole-sheet.html",
|
||||
width: 500,
|
||||
height: 380,
|
||||
});
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async getData(options = {}) {
|
||||
const sheetData = await super.getData(options);
|
||||
|
||||
sheetData.data.enrichedHtml = {
|
||||
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
sheetData.data.system.description ?? "",
|
||||
{ async: true }
|
||||
),
|
||||
};
|
||||
|
||||
return sheetData;
|
||||
}
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
import { ItemSheetL5r5e } from "./item-sheet.js";
|
||||
|
||||
/**
|
||||
* @extends {ItemSheet}
|
||||
*/
|
||||
export class TechniqueSheetL5r5e extends ItemSheetL5r5e {
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["l5r5e", "sheet", "technique"],
|
||||
template: CONFIG.l5r5e.paths.templates + "items/technique/technique-sheet.html",
|
||||
});
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async getData(options = {}) {
|
||||
const sheetData = await super.getData(options);
|
||||
|
||||
// List all available techniques type
|
||||
const types = ["core", "school", "title", "chiaroscuro"];
|
||||
if (game.settings.get(CONFIG.l5r5e.namespace, "techniques-customs")) {
|
||||
types.push("custom");
|
||||
}
|
||||
sheetData.data.techniquesList = game.l5r5e.HelpersL5r5e.getTechniquesList({ types });
|
||||
|
||||
// Invocation sub-type fields (visible only for mot_invocation)
|
||||
sheetData.data.isMotInvocation = sheetData.data.system.technique_type === "mot_invocation";
|
||||
sheetData.data.invocationTypes = [
|
||||
{ id: "general", label: game.i18n.localize("chiaroscuro.technique.invocation_types.general") },
|
||||
{ id: "neutre", label: game.i18n.localize("chiaroscuro.technique.invocation_types.neutre") },
|
||||
{ id: "precis", label: game.i18n.localize("chiaroscuro.technique.invocation_types.precis") },
|
||||
];
|
||||
sheetData.data.modeInvocationValues = [
|
||||
{ id: "-3", label: "-3" },
|
||||
{ id: "0", label: "0" },
|
||||
{ id: "3", label: "+3" },
|
||||
];
|
||||
// Convert mode_invocation to string for selectOptions matching
|
||||
sheetData.data.system.mode_invocation_str = String(sheetData.data.system.mode_invocation ?? 0);
|
||||
|
||||
// Sanitize Difficulty and Skill list
|
||||
sheetData.data.system.difficulty = TechniqueSheetL5r5e.formatDifficulty(sheetData.data.system.difficulty);
|
||||
sheetData.data.system.skill = TechniqueSheetL5r5e.translateSkillsList(
|
||||
TechniqueSheetL5r5e.formatSkillList(sheetData.data.system.skill.split(",")),
|
||||
false
|
||||
).join(", ");
|
||||
|
||||
return sheetData;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called upon form submission after form data is validated
|
||||
* @param {Event} event The initial triggering submission event
|
||||
* @param {Object} formData The object of validated form data with which to update the object
|
||||
* @returns {Promise} A Promise which resolves once the update operation has completed
|
||||
* @override
|
||||
*/
|
||||
async _updateObject(event, formData) {
|
||||
// Change the image according to the type if this is already the case
|
||||
if (
|
||||
formData["system.technique_type"] &&
|
||||
formData.img === `${CONFIG.l5r5e.paths.assets}icons/techs/${this.object.system.technique_type}.svg`
|
||||
) {
|
||||
formData.img = `${CONFIG.l5r5e.paths.assets}icons/techs/${formData["system.technique_type"]}.svg`;
|
||||
}
|
||||
|
||||
// Sanitize Difficulty and Skill list
|
||||
formData["system.difficulty"] = TechniqueSheetL5r5e.formatDifficulty(formData["system.difficulty"]);
|
||||
formData["system.skill"] = TechniqueSheetL5r5e.formatSkillList(
|
||||
TechniqueSheetL5r5e.translateSkillsList(formData["system.skill"].split(","), true)
|
||||
).join(",");
|
||||
|
||||
// Convert mode_invocation_str back to number
|
||||
if ("system.mode_invocation_str" in formData) {
|
||||
formData["system.mode_invocation"] = parseInt(formData["system.mode_invocation_str"] ?? "0", 10);
|
||||
delete formData["system.mode_invocation_str"];
|
||||
}
|
||||
|
||||
return super._updateObject(event, formData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen to html elements
|
||||
* @param {jQuery} html HTML content of the sheet.
|
||||
* @override
|
||||
*/
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// *** Everything below here is only needed if the sheet is editable ***
|
||||
if (!this.isEditable) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Autocomplete
|
||||
game.l5r5e.HelpersL5r5e.autocomplete(
|
||||
html,
|
||||
"system.difficulty",
|
||||
[
|
||||
"@T:intrigueRank",
|
||||
"@T:focus",
|
||||
"@T:martialRank",
|
||||
"@T:statusRank|max",
|
||||
"@T:strife.value|max",
|
||||
"@T:vigilance",
|
||||
"@T:vigilance|max",
|
||||
"@T:vigilance|min",
|
||||
"@T:vigilance|max(@T:statusRank)",
|
||||
],
|
||||
","
|
||||
);
|
||||
game.l5r5e.HelpersL5r5e.autocomplete(
|
||||
html,
|
||||
"system.skill",
|
||||
Object.values(TechniqueSheetL5r5e.getSkillsTranslationMap(false)),
|
||||
","
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the technique difficulty
|
||||
* @param {string} str
|
||||
* @return {string}
|
||||
*/
|
||||
static formatDifficulty(str) {
|
||||
if (str && !Number.isNumeric(str) && !CONFIG.l5r5e.regex.techniqueDifficulty.test(str)) {
|
||||
return "";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a flat map for skill translation
|
||||
* @param {boolean} bToSkillId if true flip props/values
|
||||
* @return {Object}
|
||||
*/
|
||||
static getSkillsTranslationMap(bToSkillId) {
|
||||
return Array.from(CONFIG.l5r5e.skills).reduce((acc, [id, cat]) => {
|
||||
if (bToSkillId) {
|
||||
acc[game.l5r5e.HelpersL5r5e.normalize(game.i18n.localize(`l5r5e.skills.${cat}.${id}`))] = id;
|
||||
acc[game.l5r5e.HelpersL5r5e.normalize(game.i18n.localize(`l5r5e.skills.${cat}.title`))] = cat;
|
||||
} else {
|
||||
acc[id] = game.i18n.localize(`l5r5e.skills.${cat}.${id}`);
|
||||
acc[cat] = game.i18n.localize(`l5r5e.skills.${cat}.title`);
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a list of skill and category
|
||||
* @param {string[]} aIn
|
||||
* @param {boolean} bToSkillId
|
||||
* @return {string[]}
|
||||
*/
|
||||
static translateSkillsList(aIn, bToSkillId) {
|
||||
const map = TechniqueSheetL5r5e.getSkillsTranslationMap(bToSkillId);
|
||||
return aIn.map((skill) => map[game.l5r5e.HelpersL5r5e.normalize(skill)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the technique skill list
|
||||
* @param {string[]} skillList
|
||||
* @return {string[]}
|
||||
*/
|
||||
static formatSkillList(skillList) {
|
||||
if (!skillList) {
|
||||
return "";
|
||||
}
|
||||
const categories = game.l5r5e.HelpersL5r5e.getCategoriesSkillsList();
|
||||
|
||||
// List categories
|
||||
const unqCatList = new Set();
|
||||
skillList.forEach((s) => {
|
||||
s = s?.trim();
|
||||
if (!!s && categories.has(s)) {
|
||||
unqCatList.add(s);
|
||||
}
|
||||
});
|
||||
|
||||
// List skill (not include in cat)
|
||||
const unqSkillList = new Set();
|
||||
skillList.forEach((s) => {
|
||||
s = s?.trim();
|
||||
if (!!s && CONFIG.l5r5e.skills.has(s)) {
|
||||
const cat = CONFIG.l5r5e.skills.get(s);
|
||||
if (!unqCatList.has(cat)) {
|
||||
unqSkillList.add(s);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return [...unqCatList, ...unqSkillList];
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
import { ItemSheetL5r5e } from "./item-sheet.js";
|
||||
|
||||
/**
|
||||
* @extends {ItemSheet}
|
||||
*/
|
||||
export class TitleSheetL5r5e extends ItemSheetL5r5e {
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["l5r5e", "sheet", "title"],
|
||||
template: CONFIG.l5r5e.paths.templates + "items/title/title-sheet.html",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Object|Promise}
|
||||
*/
|
||||
async getData(options = {}) {
|
||||
const sheetData = await super.getData(options);
|
||||
|
||||
// Prepare OwnedItems
|
||||
sheetData.data.embedItemsList = this._prepareEmbedItems(sheetData.data.system.items);
|
||||
|
||||
// Automatically compute the total xp cost (full price) and XP in title (cursus, some halved prices)
|
||||
const { xp_used_total, xp_used } = game.l5r5e.HelpersL5r5e.getItemsXpCost(sheetData.data.embedItemsList);
|
||||
sheetData.data.system.xp_used_total = xp_used_total;
|
||||
sheetData.data.system.xp_used = xp_used;
|
||||
|
||||
return sheetData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare Embed items
|
||||
* @param {[]|Map} itemsMap
|
||||
* @return {[]}
|
||||
* @private
|
||||
*/
|
||||
_prepareEmbedItems(itemsMap) {
|
||||
let itemsList = itemsMap;
|
||||
if (itemsMap instanceof Map) {
|
||||
itemsList = Array.from(itemsMap).map(([id, item]) => item);
|
||||
}
|
||||
|
||||
// Sort by rank desc
|
||||
itemsList.sort((a, b) => (b.system.rank || 0) - (a.system.rank || 0));
|
||||
|
||||
return itemsList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback actions which occur when a dragged element is dropped on a target.
|
||||
* @param {DragEvent} event The originating DragEvent
|
||||
* @private
|
||||
*/
|
||||
async _onDrop(event) {
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.isEditable) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check item type and subtype
|
||||
let item = await game.l5r5e.HelpersL5r5e.getDragnDropTargetObject(event);
|
||||
if (!item || item.documentName !== "Item" || !["technique", "advancement"].includes(item.type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = item.toObject(false);
|
||||
|
||||
// Check xp for techs
|
||||
if (item.type === "technique") {
|
||||
data.system.xp_cost = data.system.xp_cost > 0 ? data.system.xp_cost : CONFIG.l5r5e.xp.techniqueCost;
|
||||
data.system.xp_used = data.system.xp_cost;
|
||||
}
|
||||
|
||||
this.document.addEmbedItem(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to events from the sheet.
|
||||
* @param {jQuery} html HTML content of the sheet.
|
||||
*/
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.isEditable) {
|
||||
return;
|
||||
}
|
||||
|
||||
// *** Sub-Items management ***
|
||||
html.find(".item-add").on("click", this._addSubItem.bind(this));
|
||||
html.find(`.item-edit`).on("click", this._editSubItem.bind(this));
|
||||
html.find(`.item-delete`).on("click", this._deleteSubItem.bind(this));
|
||||
html.find(`.item-curriculum`).on("click", this._switchSubItemCurriculum.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a dialog to choose what Item to add, and add it on this Item
|
||||
* @param {Event} event
|
||||
* @return {Promise<void>}
|
||||
* @private
|
||||
*/
|
||||
async _addSubItem(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
// Show Dialog
|
||||
const selectedType = await game.l5r5e.HelpersL5r5e.showSubItemDialog(["advancement", "technique"]);
|
||||
if (!selectedType) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the new Item
|
||||
const itemId = await this.document.addEmbedItem(
|
||||
new game.l5r5e.ItemL5r5e({
|
||||
name: game.i18n.localize(`TYPES.Item.${selectedType.toLowerCase()}`),
|
||||
type: selectedType,
|
||||
img: `${CONFIG.l5r5e.paths.assets}icons/items/${selectedType}.svg`,
|
||||
})
|
||||
);
|
||||
|
||||
// Get the store object and display it
|
||||
const item = this.document.items.get(itemId);
|
||||
if (item) {
|
||||
item.sheet.render(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toogle the curriculum for this embed item
|
||||
* @param {Event} event
|
||||
* @return {Promise<void>}
|
||||
* @private
|
||||
*/
|
||||
async _switchSubItemCurriculum(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
const itemId = $(event.currentTarget).data("item-id");
|
||||
const item = this.document.getEmbedItem(itemId);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Switch the state and update
|
||||
item.system.in_curriculum = !item.system.in_curriculum;
|
||||
return this.document.updateEmbedItem(item);
|
||||
}
|
||||
}
|
||||
@@ -15,18 +15,21 @@ export class WeaponSheetL5r5e extends ItemSheetL5r5e {
|
||||
async getData(options = {}) {
|
||||
const sheetData = await super.getData(options);
|
||||
|
||||
// Martial skills only
|
||||
// Only these four skills are relevant for weapons
|
||||
const allowedSkills = ["archery", "unarmed", "melee", "invocation"];
|
||||
sheetData.data.skills = Array.from(CONFIG.l5r5e.skills)
|
||||
.filter(([id, cat]) => cat === "martial")
|
||||
.filter(([id]) => allowedSkills.includes(id))
|
||||
.map(([id, cat]) => ({
|
||||
id,
|
||||
label: "l5r5e.skills." + cat.toLowerCase() + "." + id.toLowerCase(),
|
||||
}));
|
||||
|
||||
// Weapon categories (Chiaroscuro)
|
||||
// Weapon categories (Chiaroscuro) — sorted alphabetically
|
||||
const catObj = game.l5r5e.HelpersL5r5e.getLocalizedRawObject("chiaroscuro.weapon.categories") ?? {};
|
||||
sheetData.data.weaponCategories = [{ id: "", label: "—" }].concat(
|
||||
Object.entries(catObj).map(([id, label]) => ({ id, label }))
|
||||
Object.entries(catObj)
|
||||
.map(([id, label]) => ({ id, label }))
|
||||
.sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: "base" }))
|
||||
);
|
||||
|
||||
return sheetData;
|
||||
|
||||
Reference in New Issue
Block a user