Working on 0.8.x

- Working on title
- Added property update/delete for item patterns
This commit is contained in:
Vlyan
2021-05-21 14:12:14 +02:00
parent 4350ea25ee
commit 4f9b72c63f
22 changed files with 586 additions and 101 deletions

View File

@@ -138,6 +138,7 @@
"quantity": "Quantity",
"weight": "Weight",
"properties": "Properties",
"linked_property": "linked Property",
"weapons": {
"title": "Weapons",
"damage": "Damage",

View File

@@ -138,6 +138,7 @@
"quantity": "Cantidad",
"weight": "Peso",
"properties": "Propiedades",
"linked_property": "linked Property",
"weapons": {
"title": "Armas",
"damage": "Daño",

View File

@@ -138,6 +138,7 @@
"quantity": "Quantité",
"weight": "Poids",
"properties": "Propriétés",
"linked_property": "Propriété liée",
"weapons": {
"title": "Armement",
"damage": "Dégâts de base (DDB)",

View File

@@ -1,5 +1,5 @@
{"_id":"L5RCoreItp000001","name":"Kakita Pattern","permission":{"default":0},"type":"item_pattern","data":{"in_curriculum":false,"xp_used":0,"rank":1,"bought_at_rank":0,"ring":"void","xp_cost":"6","rarity_modifier":"4","description":"","book_reference":"Shadowlands p.109"},"sort":100001,"flags":{"l5r5e":{"linkedPropertyId":"L5RCorePro000017"}},"img":"systems/l5r5e/assets/icons/items/item_pattern.svg","effects":[]}
{"_id":"L5RCoreItp000002","name":"Kenzō Blade","permission":{"default":0},"type":"item_pattern","data":{"in_curriculum":false,"xp_used":0,"rank":1,"bought_at_rank":0,"ring":"void","xp_cost":"8","rarity_modifier":"5","description":"","book_reference":"Shadowlands p.109"},"sort":100001,"flags":{"l5r5e":{"linkedPropertyId":"L5RCorePro000018"}},"img":"systems/l5r5e/assets/icons/items/item_pattern.svg","effects":[]}
{"_id":"L5RCoreItp000003","name":"Shirogane Jade Inlay","permission":{"default":0},"type":"item_pattern","data":{"in_curriculum":false,"xp_used":0,"rank":1,"bought_at_rank":0,"ring":"void","xp_cost":"3","rarity_modifier":"2","description":"","book_reference":"Shadowlands p.109"},"sort":100001,"flags":{"l5r5e":{"linkedPropertyId":"L5RCorePro000019"}},"img":"systems/l5r5e/assets/icons/items/item_pattern.svg","effects":[]}
{"_id":"L5RCoreItp000004","name":"Uchemas Technique","permission":{"default":0},"type":"item_pattern","data":{"in_curriculum":false,"xp_used":0,"rank":1,"bought_at_rank":0,"ring":"void","xp_cost":"4","rarity_modifier":"3","description":"","book_reference":"Shadowlands p.109"},"sort":100001,"flags":{"l5r5e":{"linkedPropertyId":"L5RCorePro000020"}},"img":"systems/l5r5e/assets/icons/items/item_pattern.svg","effects":[]}
{"_id":"L5RCoreItp000005","name":"Yasunori Steel","permission":{"default":0},"type":"item_pattern","data":{"in_curriculum":false,"xp_used":0,"rank":1,"bought_at_rank":0,"ring":"void","xp_cost":"5","rarity_modifier":"4","description":"","book_reference":"Shadowlands p.109"},"sort":100001,"flags":{"l5r5e":{"linkedPropertyId":"L5RCorePro000021"}},"img":"systems/l5r5e/assets/icons/items/item_pattern.svg","effects":[]}
{"_id":"L5RCoreItp000001","name":"Kakita Pattern","permission":{"default":0},"type":"item_pattern","data":{"in_curriculum":false,"xp_used":0,"rank":1,"bought_at_rank":0,"ring":"void","xp_cost":"6","rarity_modifier":"4","linked_property_id":"L5RCorePro000017","description":"","book_reference":"Shadowlands p.109"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item_pattern.svg","effects":[]}
{"_id":"L5RCoreItp000002","name":"Kenzō Blade","permission":{"default":0},"type":"item_pattern","data":{"in_curriculum":false,"xp_used":0,"rank":1,"bought_at_rank":0,"ring":"void","xp_cost":"8","rarity_modifier":"5","linked_property_id":"L5RCorePro000018","description":"","book_reference":"Shadowlands p.109"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item_pattern.svg","effects":[]}
{"_id":"L5RCoreItp000003","name":"Shirogane Jade Inlay","permission":{"default":0},"type":"item_pattern","data":{"in_curriculum":false,"xp_used":0,"rank":1,"bought_at_rank":0,"ring":"void","xp_cost":"3","rarity_modifier":"2","linked_property_id":"L5RCorePro000019","description":"","book_reference":"Shadowlands p.109"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item_pattern.svg","effects":[]}
{"_id":"L5RCoreItp000004","name":"Uchemas Technique","permission":{"default":0},"type":"item_pattern","data":{"in_curriculum":false,"xp_used":0,"rank":1,"bought_at_rank":0,"ring":"void","xp_cost":"4","rarity_modifier":"3","linked_property_id":"L5RCorePro000020","description":"","book_reference":"Shadowlands p.109"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item_pattern.svg","effects":[]}
{"_id":"L5RCoreItp000005","name":"Yasunori Steel","permission":{"default":0},"type":"item_pattern","data":{"in_curriculum":false,"xp_used":0,"rank":1,"bought_at_rank":0,"ring":"void","xp_cost":"5","rarity_modifier":"4","linked_property_id":"L5RCorePro000021","description":"","book_reference":"Shadowlands p.109"},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item_pattern.svg","effects":[]}

View File

@@ -324,6 +324,10 @@ export class BaseSheetL5r5e extends ActorSheet {
event.stopPropagation();
const type = $(event.currentTarget).data("item-type");
if (!type) {
return;
}
const titles = {
item: "ITEM.TypeItem",
armor: "ITEM.TypeArmor",
@@ -336,6 +340,10 @@ export class BaseSheetL5r5e extends ActorSheet {
item_pattern: "ITEM.TypeItem_pattern",
signature_scroll: "ITEM.TypeSignature_scroll",
};
if (!titles[type]) {
return;
}
const created = await this.actor.createEmbeddedDocuments("Item", [
{
name: game.i18n.localize(titles[type]),
@@ -343,6 +351,9 @@ export class BaseSheetL5r5e extends ActorSheet {
img: `${CONFIG.l5r5e.paths.assets}icons/items/${type}.svg`,
},
]);
if (created?.length > 0) {
return;
}
const item = this.actor.items.get(created[0].id);
// assign current school rank to the new adv/tech
@@ -385,7 +396,14 @@ export class BaseSheetL5r5e extends ActorSheet {
event.stopPropagation();
const itemId = $(event.currentTarget).data("item-id");
if (!itemId) {
return;
}
const item = this.actor.items.get(itemId);
if (!item) {
return;
}
item.sheet.render(true);
}
@@ -399,6 +417,9 @@ export class BaseSheetL5r5e extends ActorSheet {
event.stopPropagation();
const itemId = $(event.currentTarget).data("item-id");
if (!itemId) {
return;
}
// Remove 1 qty if possible
const tmpItem = this.actor.items.get(itemId);

View File

@@ -334,7 +334,7 @@ export class TwentyQuestionsDialog extends FormApplication {
if (this.object.data.step13.advantage.length > 0) {
formData["step13.skill"] = "none";
setProperty(this.object.data, "step13.disadvantage", []);
foundry.utils.setProperty(this.object.data, "step13.disadvantage", []);
}
// Update 20Q object data
@@ -364,14 +364,14 @@ export class TwentyQuestionsDialog extends FormApplication {
this.cache = {};
for (const stepName of TwentyQuestions.itemsList) {
// Check if current step value is a array
let step = getProperty(this.object.data, stepName);
let step = foundry.utils.getProperty(this.object.data, stepName);
if (!step || !Array.isArray(step)) {
step = [];
}
// Init cache if not exist
if (!hasProperty(this.cache, stepName)) {
setProperty(this.cache, stepName, []);
if (!foundry.utils.hasProperty(this.cache, stepName)) {
foundry.utils.setProperty(this.cache, stepName, []);
}
// Get linked Item, and store it in cache (delete null value and old items)
@@ -385,9 +385,9 @@ export class TwentyQuestionsDialog extends FormApplication {
continue;
}
newStep.push(id);
getProperty(this.cache, stepName).push(item);
foundry.utils.getProperty(this.cache, stepName).push(item);
}
setProperty(this.object.data, stepName, newStep);
foundry.utils.setProperty(this.object.data, stepName, newStep);
}
}
@@ -400,7 +400,7 @@ export class TwentyQuestionsDialog extends FormApplication {
roll.actor = this._actor;
await roll.roll();
setProperty(this.object.data, stepName, roll.result);
foundry.utils.setProperty(this.object.data, stepName, roll.result);
return roll.toMessage({ flavor: flavor });
}
@@ -410,7 +410,7 @@ export class TwentyQuestionsDialog extends FormApplication {
*/
_addOwnedItem(item, stepName) {
// Add to Step (uniq id only)
let step = getProperty(this.object.data, stepName);
let step = foundry.utils.getProperty(this.object.data, stepName);
if (!step) {
step = [];
}
@@ -420,7 +420,7 @@ export class TwentyQuestionsDialog extends FormApplication {
step.push(item.id);
// Add to cache
getProperty(this.cache, stepName).push(item);
foundry.utils.getProperty(this.cache, stepName).push(item);
}
/**
@@ -429,14 +429,14 @@ export class TwentyQuestionsDialog extends FormApplication {
*/
_deleteOwnedItem(stepName, itemId) {
// Delete from current step
let step = getProperty(this.object.data, stepName);
let step = foundry.utils.getProperty(this.object.data, stepName);
step = step.filter((e) => !!e && e !== itemId);
setProperty(this.object.data, stepName, step);
foundry.utils.setProperty(this.object.data, stepName, step);
// Delete from cache
let cache = getProperty(this.cache, stepName);
let cache = foundry.utils.getProperty(this.cache, stepName);
cache = cache.filter((e) => !!e && e.id !== itemId);
setProperty(this.cache, stepName, cache);
foundry.utils.setProperty(this.cache, stepName, cache);
}
/**
@@ -444,7 +444,7 @@ export class TwentyQuestionsDialog extends FormApplication {
* @private
*/
_getSkillZero(skillsList, skillsPoints, stepName) {
const stepSkillId = getProperty(this.object.data, stepName);
const stepSkillId = foundry.utils.getProperty(this.object.data, stepName);
const out = {};
Object.entries(skillsList).forEach(([cat, val]) => {
out[cat] = val.filter(

View File

@@ -267,7 +267,7 @@ export class TwentyQuestions {
// Rings - Reset to 1, and apply modifiers
CONFIG.l5r5e.stances.forEach((ring) => (actorDatas.rings[ring] = 1));
TwentyQuestions.ringList.forEach((formName) => {
const ring = getProperty(this.data, formName);
const ring = foundry.utils.getProperty(this.data, formName);
if (ring !== "none") {
actorDatas.rings[ring] = actorDatas.rings[ring] + 1;
}
@@ -278,7 +278,7 @@ export class TwentyQuestions {
actorDatas.skills[skillCat][skillId] = 0;
});
TwentyQuestions.skillList.forEach((formName) => {
const skillId = getProperty(this.data, formName);
const skillId = foundry.utils.getProperty(this.data, formName);
const skillCat = CONFIG.l5r5e.skills.get(skillId);
if (skillId !== "none") {
actorDatas.skills[skillCat][skillId] = actorDatas.skills[skillCat][skillId] + 1;
@@ -292,7 +292,7 @@ export class TwentyQuestions {
// Add items in 20Q to actor
for (const types of Object.values(itemsCache)) {
for (const item of types) {
const itemData = duplicate(item.data);
const itemData = foundry.utils.duplicate(item.data);
if (itemData.data?.bought_at_rank) {
itemData.data.bought_at_rank = 0;
}
@@ -377,7 +377,7 @@ export class TwentyQuestions {
summariesRingsOrSkills(listName) {
const store = {};
TwentyQuestions[listName].forEach((formName) => {
const id = getProperty(this.data, formName);
const id = foundry.utils.getProperty(this.data, formName);
if (!id || id === "none") {
return;
}

View File

@@ -23,7 +23,7 @@ L5R5E.techniques.set("ninjutsu", { type: "core", displayInTypes: true });
L5R5E.techniques.set("school_ability", { type: "school", displayInTypes: false });
L5R5E.techniques.set("mastery_ability", { type: "school", displayInTypes: false });
// Title
L5R5E.techniques.set("title_ability", { type: "title", displayInTypes: false });
// L5R5E.techniques.set("title_ability", { type: "title", displayInTypes: false });
// Custom
L5R5E.techniques.set("specificity", { type: "custom", displayInTypes: false });

View File

@@ -399,7 +399,7 @@ export class DicePickerDialog extends FormApplication {
// Update Actor
if (this._actor) {
const actorData = duplicate(this._actor.data.data);
const actorData = foundry.utils.duplicate(this._actor.data.data);
// Update the actor stance on initiative only
if (this.object.isInitiativeRoll) {
@@ -416,10 +416,13 @@ export class DicePickerDialog extends FormApplication {
actorData.void_points.value = Math.max(actorData.void_points.value - 1, 0);
}
// Update actor
await this._actor.update({
data: diffObject(this._actor.data.data, actorData),
});
// Update actor if needed
const updateDiff = foundry.utils.diffObject(this._actor.data.data, actorData);
if (Object.keys(updateDiff).length > 0) {
await this._actor.update({
data: foundry.utils.diffObject(this._actor.data.data, actorData),
});
}
}
// Build the formula

View File

@@ -65,7 +65,7 @@ export class GmToolsDialog extends FormApplication {
*/
async close(options = {}) {
// TODO better implementation needed : see KeyboardManager._onEscape(event, up, modifiers)
// This windows is always open, so esc key si stuck at step 2 : Object.keys(ui.windows).length > 0
// This windows is always open, so esc key is stuck at step 2 : Object.keys(ui.windows).length > 0
// Case 3 (GM) - release controlled objects
if (canvas?.ready && game.user.isGM && Object.keys(canvas.activeLayer._controlled).length) {
canvas.activeLayer.releaseAll();

View File

@@ -137,7 +137,6 @@ export class HelpersL5r5e {
} catch (err) {
console.warn(err);
}
console.log(" ***** getObjectGameOrPack", document);
return document;
}
@@ -151,8 +150,9 @@ export class HelpersL5r5e {
"armor",
"weapon",
"technique",
"peculiarity",
"property",
"peculiarity",
"advancement",
"title",
"bond",
"signature_scroll",

View File

@@ -1,4 +1,12 @@
export class ItemL5r5e extends Item {
/**
* A reference to the Collection of embedded Item instances in the document, indexed by _id.
* @returns {Collection<BaseItem>}
*/
get items() {
return this.data.data.items || null;
}
/**
* Create a new entity using provided input data
* @override
@@ -9,4 +17,179 @@ export class ItemL5r5e extends Item {
}
return super.create(data, context);
}
/**
* Update this Document using incremental data, saving it to the database.
* @see {@link Document.updateDocuments}
* @param {object} [data={}] Differential update data which modifies the existing values of this document data
* @param {DocumentModificationContext} [context={}] Additional context which customizes the update workflow
* @returns {Promise<Document>} The updated Document instance
*/
async update(data = {}, context = {}) {
// Regular
if (!this.data.data.parentId) {
return super.update(data, context);
}
// **** Embed Items, need to get the parents ****
const parentItem = this.getItemFromParentId();
if (!parentItem) {
console.warn(`Embed parentItem not found`);
return;
}
// Merge (DocumentData cannot be set)
const result = foundry.utils.mergeObject(this.data, foundry.utils.expandObject(data));
if (result.name) {
this.data.name = result.name;
}
if (result.img) {
this.data.img = result.img;
}
if (result.data) {
this.data.data = result.data;
}
// Update
await parentItem.updateEmbedItem(this.data.toObject(false));
// Return new value for sheet
return new Promise((resolve) => resolve(this));
}
/** @override */
prepareData() {
super.prepareData();
// Prepare Embed items
if (!(this.data.data.items instanceof Map)) {
const itemsData = Array.isArray(this.data.data.items) ? this.data.data.items : [];
this.data.data.items = new Map();
itemsData.forEach((item) => {
this.addEmbedItem(item, { save: false, newId: false });
});
}
}
// ***** parent ids management *****
/**
* Return a string with idemId + actorId if any
* @return {string} itemId|actor
*/
getParentsIds() {
return this.id + (this.actor?.data?._id ? `|${this.actor.data._id}` : "");
}
/**
* Return the Item Object for the "parentId"
* @return {ItemL5r5e|null}
*/
getItemFromParentId() {
let parentItem;
let [parentItemId, parentActorId] = this.data.data.parentId.split("|");
if (parentActorId) {
// Actor item object
const parentActor = parentActorId ? game.actors.get(parentActorId) : null;
parentItem = parentActor?.items.get(parentItemId);
} else {
// World Object
parentItem = game.items.get(parentItemId);
}
return parentItem;
}
// ***** Embedded items management *****
/**
* Shortcut for this.data.data.items.get
* @param id
* @return {ItemL5r5e|null}
*/
getEmbedItem(id) {
return this.items?.get(id) || null;
}
/**
* Add a Embed Item
* @param {ItemL5r5e} item Object to add
* @param {boolean} save if we save in db or not (used internally)
* @param {boolean} newId if we change the id
* @return {Promise<void>}
*/
async addEmbedItem(item, { save = true, newId = true } = {}) {
if (!item) {
return;
}
if (!(item instanceof Item) && item._id) {
// Data -> Item
item = new ItemL5r5e(item);
}
// New id
if (newId) {
item.data._id = foundry.utils.randomID();
}
// Tag parent (flags won't work as we have no id in db)
item.data.data.parentId = this.getParentsIds();
// Object
this.data.data.items.set(item.data._id, item);
// TODO add bonus from actor
if (this.actor instanceof Actor) {
// const item = this.data.data.items.get(id);
}
if (save) {
await this.saveEmbedItems();
}
}
/**
* Update a Embed Item
* @param {ItemL5r5e} item Object to add
* @param {boolean} save if we save in db or not (used internally)
* @return {Promise<void>}
*/
async updateEmbedItem(item, { save = true } = {}) {
await this.addEmbedItem(item, { save, newId: false });
}
/**
* Delete the Embed Item and clear the actor bonus if any
* @param {ItemL5r5e} item Object to add
* @param {boolean} save if we save in db or not (used internally)
* @return {Promise<void>}
*/
async deleteEmbedItem(id, { save = true } = {}) {
if (!this.data.data.items.has(id)) {
return;
}
// TODO remove bonus from actor
if (this.actor instanceof Actor) {
// const item = this.data.data.items.get(id);
}
// Remove the embed item
this.data.data.items.delete(id);
if (save) {
await this.saveEmbedItems();
}
}
/**
* Save all the Embed Items
* @return {Promise<void>}
*/
async saveEmbedItems() {
await this.update({
"data.items": Array.from(this.data.data.items).map(([id, item]) => item.data.toObject(false)),
});
this.sheet.render(false);
}
}

View File

@@ -14,4 +14,121 @@ export class ItemPatternSheetL5r5e extends ItemSheetL5r5e {
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description" }],
});
}
/**
* @return {Object|Promise}
*/
async getData(options = {}) {
const sheetData = await super.getData(options);
sheetData.data.dtypes = ["String", "Number", "Boolean"];
sheetData.data.ringsList = game.l5r5e.HelpersL5r5e.getRingsList();
// 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.data.linked_property_id) {
const linkedProperty = await game.l5r5e.HelpersL5r5e.getObjectGameOrPack({
id: sheetData.data.data.linked_property_id,
type: "Item",
});
if (linkedProperty) {
return {
id: linkedProperty.data._id,
name: linkedProperty.data.name,
};
}
}
return null;
}
/**
* Subscribe to events from the sheet.
* @param html HTML content of the sheet.
*/
activateListeners(html) {
super.activateListeners(html);
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) {
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.options.editable) {
return;
}
// Only property allowed here
let item = await game.l5r5e.HelpersL5r5e.getDragnDropTargetObject(event);
if (!item || item.documentName !== "Item" || item.data.type !== "property") {
return;
}
// Set the new property, and update
this.document.data.data.linked_property_id = item.id;
this.document.update({
data: {
linked_property_id: this.document.data.data.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.data.data.linked_property_id,
type: "Item",
});
if (linkedProperty) {
name = linkedProperty.data.name;
}
const callback = async () => {
this.document.data.data.linked_property_id = null;
this.document.update({
data: {
linked_property_id: this.document.data.data.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
);
}
}

View File

@@ -142,8 +142,11 @@ export class ItemSheetL5r5e extends ItemSheet {
}
// Specific ItemPattern's drop, get the associated props instead
if (item.data.type === "item_pattern" && item.data.flags.l5r5e?.linkedPropertyId) {
item = await game.packs.get("l5r5e.core-properties").getDocument(item.data.flags.l5r5e.linkedPropertyId);
if (item.data.type === "item_pattern" && item.data.data.linked_property_id) {
item = await game.l5r5e.HelpersL5r5e.getObjectGameOrPack({
id: item.data.data.linked_property_id,
type: "Item",
});
}
// Final object has to be a property
@@ -179,6 +182,8 @@ export class ItemSheetL5r5e extends ItemSheet {
/**
* Delete a property from the current item
* @param {Event} event
* @return {Promise<void>}
* @private
*/
_deleteProperty(event) {
@@ -214,4 +219,43 @@ export class ItemSheetL5r5e extends ItemSheet {
callback
);
}
/**
* Add a embed item
* @param event
* @private
*/
_addSubItem(event) {
event.preventDefault();
event.stopPropagation();
const itemId = $(event.currentTarget).data("item-id");
console.log("TODO _addSubItem", itemId); // TODO _addSubItem
}
/**
* Add a embed item
* @param event
* @private
*/
_editSubItem(event) {
event.preventDefault();
event.stopPropagation();
const itemId = $(event.currentTarget).data("item-id");
const item = this.document.items.get(itemId);
if (item) {
item.sheet.render(true);
}
}
/**
* Delete a embed item
* @param event
* @private
*/
_deleteSubItem(event) {
event.preventDefault();
event.stopPropagation();
const itemId = $(event.currentTarget).data("item-id");
this.document.deleteEmbedItem(itemId);
}
}

View File

@@ -14,4 +14,95 @@ export class TitleSheetL5r5e extends ItemSheetL5r5e {
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description" }],
});
}
/**
* @return {Object|Promise}
*/
async getData(options = {}) {
const sheetData = await super.getData(options);
sheetData.data.dtypes = ["String", "Number", "Boolean"];
sheetData.data.ringsList = game.l5r5e.HelpersL5r5e.getRingsList();
console.log(sheetData.data.data.items); // todo tmp
// Prepare OwnedItems
sheetData.data.embedItemsList = this._prepareEmbedItems(sheetData.data.data.items);
console.log(sheetData); // todo tmp
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.data);
}
// Sort by rank desc
itemsList.sort((a, b) => (b.data.rank || 0) - (a.data.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.options.editable) {
return;
}
// Check item type and subtype
let item = await game.l5r5e.HelpersL5r5e.getDragnDropTargetObject(event);
if (!item || (item.documentName !== "Item" && !["technique", "advancement"].includes(item.data.type))) {
return;
}
const data = item.data.toJSON();
console.log("------ data", data); // todo tmp
this.document.addEmbedItem(data);
console.log(this.document); // todo tmp
}
/**
* Subscribe to events from the sheet.
* @param html HTML content of the sheet.
*/
activateListeners(html) {
super.activateListeners(html);
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) {
return;
}
// *** Items : add, edit, delete ***
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));
}
/**
* 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
* @abstract
*/
// async _updateObject(event, formData) {
// console.log("------- _updateObject.", formData); // todo TMP
// return super._updateObject(event, formData);
// }
}

View File

@@ -38,7 +38,7 @@ export class MigrationL5r5e {
const updateData = MigrationL5r5e._migrateActorData(a.data);
if (!isObjectEmpty(updateData)) {
console.log(`Migrating Actor entity ${a.name}`);
await a.update(updateData, { enforceTypes: false });
await a.update(updateData, { enforceTypes: false }); // TODO use Actor.updateDocuments(data, context) for multiple actors
}
} catch (err) {
err.message = `Failed L5R5e system migration for Actor ${a.name}: ${err.message}`;
@@ -52,7 +52,7 @@ export class MigrationL5r5e {
const updateData = MigrationL5r5e._migrateItemData(i.data);
if (!isObjectEmpty(updateData)) {
console.log(`Migrating Item entity ${i.name}`);
await i.update(updateData, { enforceTypes: false });
await i.update(updateData, { enforceTypes: false }); // TODO use Item.updateDocuments(data, context) for multiple actors
}
} catch (err) {
err.message = `Failed L5R5e system migration for Item ${i.name}: ${err.message}`;
@@ -66,7 +66,7 @@ export class MigrationL5r5e {
const updateData = MigrationL5r5e._migrateSceneData(s.data);
if (!isObjectEmpty(updateData)) {
console.log(`Migrating Scene entity ${s.name}`);
await s.update(updateData, { enforceTypes: false });
await s.update(updateData, { enforceTypes: false }); // TODO use Scene.updateDocuments(data, context) for multiple actors
}
} catch (err) {
err.message = `Failed L5R5e system migration for Scene ${s.name}: ${err.message}`;
@@ -132,7 +132,7 @@ export class MigrationL5r5e {
// Save the entry, if data was changed
updateData["_id"] = ent._id;
await pack.updateEntity(updateData);
await pack.updateEntity(updateData); // TODO use Item/Actor.updateDocuments(data, context) for multiple actors
console.log(`Migrated ${entity} entity ${ent.name} in Compendium ${pack.collection}`);
} catch (err) {
// Handle migration failures

View File

@@ -1,62 +1,61 @@
export const PreloadTemplates = async function () {
const templatePaths = [
const tpl = CONFIG.l5r5e.paths.templates;
return loadTemplates([
// Add paths to "systems/l5r5e/templates"
// *** Actors : PC ***
"systems/l5r5e/templates/actors/character/advancement-school.html",
"systems/l5r5e/templates/actors/character/advancement-others.html",
"systems/l5r5e/templates/actors/character/attributes.html",
"systems/l5r5e/templates/actors/character/category.html",
"systems/l5r5e/templates/actors/character/conflict.html",
"systems/l5r5e/templates/actors/character/experience.html",
"systems/l5r5e/templates/actors/character/identity.html",
"systems/l5r5e/templates/actors/character/inventory.html",
"systems/l5r5e/templates/actors/character/narrative.html",
"systems/l5r5e/templates/actors/character/rings.html",
"systems/l5r5e/templates/actors/character/skill.html",
"systems/l5r5e/templates/actors/character/social.html",
"systems/l5r5e/templates/actors/character/stance.html",
"systems/l5r5e/templates/actors/character/techniques.html",
"systems/l5r5e/templates/actors/character/twenty-questions-item.html",
`${tpl}actors/character/advancement-school.html`,
`${tpl}actors/character/advancement-others.html`,
`${tpl}actors/character/attributes.html`,
`${tpl}actors/character/category.html`,
`${tpl}actors/character/conflict.html`,
`${tpl}actors/character/experience.html`,
`${tpl}actors/character/identity.html`,
`${tpl}actors/character/inventory.html`,
`${tpl}actors/character/narrative.html`,
`${tpl}actors/character/rings.html`,
`${tpl}actors/character/skill.html`,
`${tpl}actors/character/social.html`,
`${tpl}actors/character/stance.html`,
`${tpl}actors/character/techniques.html`,
`${tpl}actors/character/twenty-questions-item.html`,
// *** Actors : Npc ***
"systems/l5r5e/templates/actors/npc/attributes.html",
"systems/l5r5e/templates/actors/npc/conflict.html",
"systems/l5r5e/templates/actors/npc/identity.html",
"systems/l5r5e/templates/actors/npc/inventory.html",
"systems/l5r5e/templates/actors/npc/narrative.html",
"systems/l5r5e/templates/actors/npc/rings.html",
"systems/l5r5e/templates/actors/npc/social.html",
"systems/l5r5e/templates/actors/npc/skill.html",
"systems/l5r5e/templates/actors/npc/techniques.html",
`${tpl}actors/npc/attributes.html`,
`${tpl}actors/npc/conflict.html`,
`${tpl}actors/npc/identity.html`,
`${tpl}actors/npc/inventory.html`,
`${tpl}actors/npc/narrative.html`,
`${tpl}actors/npc/rings.html`,
`${tpl}actors/npc/social.html`,
`${tpl}actors/npc/skill.html`,
`${tpl}actors/npc/techniques.html`,
// *** Items ***
"systems/l5r5e/templates/items/advancement/advancement-entry.html",
"systems/l5r5e/templates/items/advancement/advancement-sheet.html",
"systems/l5r5e/templates/items/armor/armors.html",
"systems/l5r5e/templates/items/armor/armor-entry.html",
"systems/l5r5e/templates/items/armor/armor-sheet.html",
"systems/l5r5e/templates/items/bond/bond-entry.html",
"systems/l5r5e/templates/items/bond/bond-sheet.html",
"systems/l5r5e/templates/items/item/items.html",
"systems/l5r5e/templates/items/item/item-entry.html",
"systems/l5r5e/templates/items/item/item-value.html",
"systems/l5r5e/templates/items/item/item-sheet.html",
"systems/l5r5e/templates/items/item/item-infos.html",
"systems/l5r5e/templates/items/item-pattern/item-pattern-entry.html",
"systems/l5r5e/templates/items/item-pattern/item-pattern-sheet.html",
"systems/l5r5e/templates/items/peculiarity/peculiarity-entry.html",
"systems/l5r5e/templates/items/peculiarity/peculiarity-sheet.html",
"systems/l5r5e/templates/items/property/properties.html",
"systems/l5r5e/templates/items/property/property-entry.html",
"systems/l5r5e/templates/items/property/property-sheet.html",
"systems/l5r5e/templates/items/signature-scroll/signature-scroll-entry.html",
"systems/l5r5e/templates/items/signature-scroll/signature-scroll-sheet.html",
"systems/l5r5e/templates/items/technique/technique-entry.html",
"systems/l5r5e/templates/items/technique/technique-sheet.html",
"systems/l5r5e/templates/items/title/title-entry.html",
"systems/l5r5e/templates/items/title/title-sheet.html",
"systems/l5r5e/templates/items/weapon/weapons.html",
"systems/l5r5e/templates/items/weapon/weapon-entry.html",
"systems/l5r5e/templates/items/weapon/weapon-sheet.html",
];
return loadTemplates(templatePaths);
`${tpl}items/advancement/advancement-entry.html`,
`${tpl}items/advancement/advancement-sheet.html`,
`${tpl}items/armor/armors.html`,
`${tpl}items/armor/armor-entry.html`,
`${tpl}items/armor/armor-sheet.html`,
`${tpl}items/bond/bond-entry.html`,
`${tpl}items/bond/bond-sheet.html`,
`${tpl}items/item/items.html`,
`${tpl}items/item/item-entry.html`,
`${tpl}items/item/item-value.html`,
`${tpl}items/item/item-sheet.html`,
`${tpl}items/item/item-infos.html`,
`${tpl}items/item-pattern/item-pattern-entry.html`,
`${tpl}items/item-pattern/item-pattern-sheet.html`,
`${tpl}items/peculiarity/peculiarity-entry.html`,
`${tpl}items/peculiarity/peculiarity-sheet.html`,
`${tpl}items/property/properties.html`,
`${tpl}items/property/property-entry.html`,
`${tpl}items/property/property-sheet.html`,
`${tpl}items/signature-scroll/signature-scroll-entry.html`,
`${tpl}items/signature-scroll/signature-scroll-sheet.html`,
`${tpl}items/technique/technique-entry.html`,
`${tpl}items/technique/technique-sheet.html`,
`${tpl}items/title/title-entry.html`,
`${tpl}items/title/title-sheet.html`,
`${tpl}items/weapon/weapons.html`,
`${tpl}items/weapon/weapon-entry.html`,
`${tpl}items/weapon/weapon-sheet.html`,
]);
};

View File

@@ -155,7 +155,9 @@
"templates": {
"basics": {
"book_reference": "",
"description": ""
"description": "",
"parent_id": null,
"items": []
},
"advancement": {
"in_curriculum": false,
@@ -214,7 +216,8 @@
},
"title": {
"templates": ["basics", "advancement"],
"xp_cost": 3
"xp_cost": 3,
"advancements": []
},
"bond": {
"templates": ["basics", "advancement"],
@@ -223,6 +226,7 @@
},
"item_pattern": {
"templates": ["basics", "advancement"],
"linked_property_id": null,
"rarity_modifier": "",
"xp_cost": 3
},

View File

@@ -102,6 +102,13 @@
<button id="finalize" name="finalize" type="button" {{#if data.submitDisabled}}disabled{{/if}}>
{{ localize 'l5r5e.roll_n_keep.bt_validate' }} <i class="fas fa-arrow-circle-right"></i>
</button>
{{!-- Symbols Helpers --}}
<div>
<i class="i_success"></i> {{localize 'l5r5e.chatdices.successes'}}
| <i class="i_explosive"></i> {{localize 'l5r5e.chatdices.explosives'}}
| <i class="i_opportunity"></i> {{localize 'l5r5e.chatdices.opportunities'}}
| <i class="i_strife"></i> {{localize 'l5r5e.chatdices.strife'}}
</div>
{{else}}
<table>
{{!-- Non editable DiceList history --}}

View File

@@ -27,6 +27,17 @@
{{ localize 'l5r5e.bought_at_rank' }}
<input class="select-on-focus" type="number" name="data.bought_at_rank" value="{{document.data.data.bought_at_rank}}" data-dtype="Number" min="0" placeholder="0"/>
</label>
<label class="attribute">
{{ localize 'l5r5e.linked_property' }}
{{#if data.linkedProperty}}
<ul class="item-properties">
<li>{{{ data.linkedProperty.name }}}</li>
<li data-item-id="{{data.linkedProperty.id}}" class="item-control linked-property-delete" title="{{localize 'Delete'}}"> <i class="fas fa-trash"></i></li>
</ul>
{{else}}
-
{{/if}}
</label>
</article>
{{> 'systems/l5r5e/templates/items/item/item-infos.html'}}
</section>

View File

@@ -32,7 +32,6 @@
{{!-- Embbed advancements --}}
<article class="tab experience" data-group="primary" data-tab="experience">
{{!-- TODO --}}
{{!-- Others progession (does not count in school xp) --}}
<fieldset class="xp-spent xp-spent-body">
<legend class="tools">{{localize 'l5r5e.advancements.title'}} <a data-item-type="advancement-others" class="advancement-others-control item-add" title="{{localize 'l5r5e.global.add'}}"><i class="fas fa-plus"></i></a></legend>
@@ -48,7 +47,7 @@
</tr>
</thead>
<tbody class="flex">
{{#each data.advancementsOthers as |advancement advancementId|}}
{{#each data.embedItemsList as |advancement|}}
{{> 'systems/l5r5e/templates/actors/character/advancement-others.html' advancement=advancement editable=../options.editable}}
{{/each}}
</tbody>