Working on 0.8.x
- Title's Advancements are now reflected on actor - Migration update
This commit is contained in:
@@ -108,4 +108,65 @@ export class ActorL5r5e extends Actor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Ring/Skill point to the current actor if the item is a advancement
|
||||
* @param {Item} item
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async addBonus(item) {
|
||||
return this._updateActorFromAdvancement(item, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a Ring/Skill point to the current actor if the item is a advancement
|
||||
* @param {Item} item
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async removeBonus(item) {
|
||||
return this._updateActorFromAdvancement(item, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter Actor skill/ring from a advancement
|
||||
* @param {Item} item
|
||||
* @param {boolean} isAdd True=add, false=remove
|
||||
* @return {Promise<void>}
|
||||
* @private
|
||||
*/
|
||||
async _updateActorFromAdvancement(item, isAdd) {
|
||||
if (item && item.type === "advancement") {
|
||||
const actor = foundry.utils.duplicate(this.data.data);
|
||||
const itemData = item.data.data;
|
||||
if (itemData.advancement_type === "ring") {
|
||||
// Ring
|
||||
if (isAdd) {
|
||||
actor.rings[itemData.ring] = Math.min(9, actor.rings[itemData.ring] + 1);
|
||||
} else {
|
||||
actor.rings[itemData.ring] = Math.max(1, actor.rings[itemData.ring] - 1);
|
||||
}
|
||||
} else {
|
||||
// Skill
|
||||
const skillCatId = CONFIG.l5r5e.skills.get(itemData.skill);
|
||||
if (skillCatId) {
|
||||
if (isAdd) {
|
||||
actor.skills[skillCatId][itemData.skill] = Math.min(
|
||||
9,
|
||||
actor.skills[skillCatId][itemData.skill] + 1
|
||||
);
|
||||
} else {
|
||||
actor.skills[skillCatId][itemData.skill] = Math.max(
|
||||
0,
|
||||
actor.skills[skillCatId][itemData.skill] - 1
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update Actor
|
||||
await this.update({
|
||||
data: foundry.utils.diffObject(this.data.data, actor),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,9 +58,19 @@ export class BaseSheetL5r5e extends ActorSheet {
|
||||
|
||||
// Add tech the character knows
|
||||
sheetData.items.forEach((item) => {
|
||||
if (item.type === "technique") {
|
||||
out[item.data.technique_type].push(item);
|
||||
}
|
||||
switch (item.type) {
|
||||
case "technique":
|
||||
out[item.data.technique_type].push(item);
|
||||
break;
|
||||
|
||||
case "title":
|
||||
Array.from(item.data.items).forEach(([id, embedItem]) => {
|
||||
if (embedItem.data.type === "technique") {
|
||||
out[embedItem.data.data.technique_type].push(embedItem.data);
|
||||
}
|
||||
});
|
||||
break;
|
||||
} //swi
|
||||
});
|
||||
|
||||
// Remove unused techs
|
||||
@@ -170,35 +180,44 @@ export class BaseSheetL5r5e extends ActorSheet {
|
||||
) {
|
||||
return;
|
||||
}
|
||||
item = item.toJSON();
|
||||
|
||||
// Dropped a item with same "id" as one owned, add qte instead
|
||||
if (item.data.quantity && this.actor.data.items) {
|
||||
const tmpItem = this.actor.data.items.find((e) => e.name === item.name && e.type === item.type);
|
||||
if (item.data.data.quantity && this.actor.data.items) {
|
||||
const tmpItem = this.actor.data.items.find((e) => e.name === item.data.name && e.type === item.data.type);
|
||||
if (tmpItem && this._modifyQuantity(tmpItem.id, 1)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Item subtype specific
|
||||
switch (item.type) {
|
||||
switch (item.data.type) {
|
||||
case "bond": // no break
|
||||
case "advancement": // no break
|
||||
case "peculiarity": // no break
|
||||
case "item_pattern": // no break
|
||||
case "signature_scroll":
|
||||
// Modify the bought at rank to the current actor rank
|
||||
if (this.actor.data.data.identity?.school_rank) {
|
||||
item.data.bought_at_rank = this.actor.data.data.identity.school_rank;
|
||||
item.data.data.bought_at_rank = this.actor.data.data.identity.school_rank;
|
||||
}
|
||||
break;
|
||||
|
||||
case "advancement":
|
||||
// Modify the bought at rank to the current actor rank
|
||||
if (this.actor.data.data.identity?.school_rank) {
|
||||
item.data.data.bought_at_rank = this.actor.data.data.identity.school_rank;
|
||||
}
|
||||
|
||||
// Specific advancements, remove 1 to selected ring/skill
|
||||
await this.actor.addBonus(item);
|
||||
break;
|
||||
|
||||
case "technique":
|
||||
// School_ability and mastery_ability, allow only 1 per type
|
||||
if (CONFIG.l5r5e.techniques.get(item.data.technique_type)?.type === "school") {
|
||||
if (CONFIG.l5r5e.techniques.get(item.data.data.technique_type)?.type === "school") {
|
||||
if (
|
||||
Array.from(this.actor.items).some(
|
||||
(e) => e.type === "technique" && e.data.data.technique_type === item.data.technique_type
|
||||
(e) =>
|
||||
e.type === "technique" && e.data.data.technique_type === item.data.data.technique_type
|
||||
)
|
||||
) {
|
||||
ui.notifications.info(game.i18n.localize("l5r5e.techniques.only_one"));
|
||||
@@ -206,24 +225,25 @@ export class BaseSheetL5r5e extends ActorSheet {
|
||||
}
|
||||
|
||||
// No cost for schools
|
||||
item.data.xp_cost = 0;
|
||||
item.data.xp_used = 0;
|
||||
item.data.in_curriculum = true;
|
||||
item.data.data.xp_cost = 0;
|
||||
item.data.data.xp_used = 0;
|
||||
item.data.data.in_curriculum = true;
|
||||
} else {
|
||||
// Check if technique is allowed for this character
|
||||
if (!game.user.isGM && !this.actor.data.data.techniques[item.data.technique_type]) {
|
||||
if (!game.user.isGM && !this.actor.data.data.techniques[item.data.data.technique_type]) {
|
||||
ui.notifications.info(game.i18n.localize("l5r5e.techniques.not_allowed"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Verify cost
|
||||
item.data.xp_cost = item.data.xp_cost > 0 ? item.data.xp_cost : CONFIG.l5r5e.xp.techniqueCost;
|
||||
item.data.xp_used = item.data.xp_cost;
|
||||
item.data.data.xp_cost =
|
||||
item.data.data.xp_cost > 0 ? item.data.data.xp_cost : CONFIG.l5r5e.xp.techniqueCost;
|
||||
item.data.data.xp_used = item.data.data.xp_cost;
|
||||
}
|
||||
|
||||
// Modify the bought at rank to the current actor rank
|
||||
if (this.actor.data.data.identity?.school_rank) {
|
||||
item.data.bought_at_rank = this.actor.data.data.identity.school_rank;
|
||||
item.data.data.bought_at_rank = this.actor.data.data.identity.school_rank;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -234,7 +254,7 @@ export class BaseSheetL5r5e extends ActorSheet {
|
||||
return;
|
||||
}
|
||||
|
||||
return this._onDropItemCreate(item);
|
||||
return this._onDropItemCreate(item.data.toObject(false));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -395,12 +415,25 @@ export class BaseSheetL5r5e extends ActorSheet {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
let item;
|
||||
const itemId = $(event.currentTarget).data("item-id");
|
||||
if (!itemId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const item = this.actor.items.get(itemId);
|
||||
const itemParentId = $(event.currentTarget).data("item-parent-id");
|
||||
if (itemParentId) {
|
||||
// Embed Item
|
||||
const parentItem = this.actor.items.get(itemParentId);
|
||||
if (!parentItem) {
|
||||
return;
|
||||
}
|
||||
item = parentItem.items.get(itemId);
|
||||
} else {
|
||||
// Regular item
|
||||
item = this.actor.items.get(itemId);
|
||||
}
|
||||
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
@@ -421,35 +454,20 @@ export class BaseSheetL5r5e extends ActorSheet {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove 1 qty if possible
|
||||
const tmpItem = this.actor.items.get(itemId);
|
||||
if (tmpItem && tmpItem.data.data.quantity > 1 && this._modifyQuantity(tmpItem.id, -1)) {
|
||||
if (!tmpItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove 1 qty if possible
|
||||
if (tmpItem.data.data.quantity > 1 && this._modifyQuantity(tmpItem.id, -1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const callback = async () => {
|
||||
// Specific advancements, remove 1 to selected ring/skill
|
||||
if (tmpItem.type === "advancement") {
|
||||
const actor = duplicate(this.actor.data.data);
|
||||
const itmData = tmpItem.data.data;
|
||||
if (itmData.advancement_type === "ring") {
|
||||
// Ring
|
||||
actor.rings[itmData.ring] = Math.max(1, actor.rings[itmData.ring] - 1);
|
||||
} else {
|
||||
// Skill
|
||||
const skillCatId = CONFIG.l5r5e.skills.get(itmData.skill);
|
||||
if (skillCatId) {
|
||||
actor.skills[skillCatId][itmData.skill] = Math.max(
|
||||
0,
|
||||
actor.skills[skillCatId][itmData.skill] - 1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Update Actor
|
||||
this.actor.update({
|
||||
data: diffObject(this.actor.data.data, actor),
|
||||
});
|
||||
await this.actor.removeBonus(tmpItem);
|
||||
}
|
||||
return this.actor.deleteEmbeddedDocuments("Item", [itemId]);
|
||||
};
|
||||
|
||||
@@ -49,13 +49,10 @@ export class CharacterSheetL5r5e extends BaseSheetL5r5e {
|
||||
// Split Money
|
||||
sheetData.data.data.money = this._zeniToMoney(this.actor.data.data.zeni);
|
||||
|
||||
// Split school advancements by rank, and calculate xp spent
|
||||
// Split school advancements by rank, and calculate xp spent and add it to total
|
||||
this._prepareSchoolAdvancement(sheetData);
|
||||
|
||||
// Titles
|
||||
this._prepareTitles(sheetData);
|
||||
|
||||
// Others
|
||||
// Split Others advancements, and calculate xp spent and add it to total
|
||||
this._prepareOthersAdvancement(sheetData);
|
||||
|
||||
// Total
|
||||
@@ -105,13 +102,6 @@ export class CharacterSheetL5r5e extends BaseSheetL5r5e {
|
||||
.activate("advancement_rank_" + (this.actor.data.data.identity.school_rank || 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare Titles, and get xp spend
|
||||
*/
|
||||
_prepareTitles(sheetData) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the school advancement, calculate the total xp spent and the current total xp spent by rank
|
||||
*/
|
||||
@@ -148,12 +138,23 @@ export class CharacterSheetL5r5e extends BaseSheetL5r5e {
|
||||
* Prepare Bonds, Item Pattern, Signature Scroll and get xp spend
|
||||
*/
|
||||
_prepareOthersAdvancement(sheetData) {
|
||||
// Split OthersAdvancement from items
|
||||
sheetData.data.advancementsOthers = sheetData.items.filter((item) =>
|
||||
["bond", "item_pattern", "title", "signature_scroll"].includes(item.type)
|
||||
);
|
||||
|
||||
// Sort by rank desc
|
||||
// sheetData.data.bondsList.sort((a, b) => (b.data.rank || 0) - (a.data.rank || 0));
|
||||
sheetData.data.advancementsOthers.sort((a, b) => (b.data.rank || 0) - (a.data.rank || 0));
|
||||
|
||||
// Total xp spent
|
||||
sheetData.data.advancementsOthersTotalXp = sheetData.data.advancementsOthers.reduce(
|
||||
(acc, item) => acc + (item.data.xp_used || 0),
|
||||
0
|
||||
);
|
||||
|
||||
// Update the total spent
|
||||
sheetData.data.data.xp_spent =
|
||||
parseInt(sheetData.data.data.xp_spent) + sheetData.data.advancementsOthersTotalXp;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,6 +178,12 @@ export class CharacterSheetL5r5e extends BaseSheetL5r5e {
|
||||
return super._updateObject(event, formData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a sum in Zeni to Zeni, Bu and Koku
|
||||
* @param {number} zeni
|
||||
* @return {{bu: number, koku: number, zeni: number}}
|
||||
* @private
|
||||
*/
|
||||
_zeniToMoney(zeni) {
|
||||
const money = {
|
||||
koku: 0,
|
||||
@@ -196,6 +203,14 @@ export class CharacterSheetL5r5e extends BaseSheetL5r5e {
|
||||
return money;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a sum in Zeni, Bu and Koku to Zeni
|
||||
* @param {number} koku
|
||||
* @param {number} bu
|
||||
* @param {number} zeni
|
||||
* @return {number}
|
||||
* @private
|
||||
*/
|
||||
_moneyToZeni(koku, bu, zeni) {
|
||||
return Math.floor(koku * CONFIG.l5r5e.money[0]) + Math.floor(bu * CONFIG.l5r5e.money[1]) + Math.floor(zeni);
|
||||
}
|
||||
|
||||
@@ -287,11 +287,14 @@ export class TwentyQuestions {
|
||||
|
||||
// Clear and add items to actor
|
||||
const deleteIds = actor.data.items.map((e) => e.id);
|
||||
await actor.deleteEmbeddedDocuments("Item", deleteIds);
|
||||
if (deleteIds.length > 0) {
|
||||
await actor.deleteEmbeddedDocuments("Item", deleteIds);
|
||||
}
|
||||
|
||||
// Add items in 20Q to actor
|
||||
for (const types of Object.values(itemsCache)) {
|
||||
for (const item of types) {
|
||||
const newItemsData = [];
|
||||
Object.values(itemsCache).forEach((types) => {
|
||||
types.forEach((item) => {
|
||||
const itemData = foundry.utils.duplicate(item.data);
|
||||
if (itemData.data?.bought_at_rank) {
|
||||
itemData.data.bought_at_rank = 0;
|
||||
@@ -299,8 +302,11 @@ export class TwentyQuestions {
|
||||
if (itemData.data?.xp_spent) {
|
||||
itemData.data.xp_spent = 0;
|
||||
}
|
||||
await actor.createEmbeddedDocuments("Item", [itemData]);
|
||||
}
|
||||
newItemsData.push(itemData);
|
||||
});
|
||||
});
|
||||
if (newItemsData.length > 0) {
|
||||
await actor.createEmbeddedDocuments("Item", newItemsData);
|
||||
}
|
||||
|
||||
// Update actor
|
||||
|
||||
@@ -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 });
|
||||
|
||||
|
||||
@@ -71,14 +71,14 @@ export class L5rBaseDie extends DiceTerm {
|
||||
* Evaluate the roll term, populating the results Array
|
||||
* @override
|
||||
*/
|
||||
evaluate({ minimize = false, maximize = false } = {}) {
|
||||
evaluate({ minimize = false, maximize = false, async = false } = {}) {
|
||||
if (this._evaluated) {
|
||||
throw new Error(`This ${this.constructor.name} has already been evaluated and is immutable`);
|
||||
}
|
||||
|
||||
// Roll the initial number of dice
|
||||
for (let n = 1; n <= this.number; n++) {
|
||||
this.roll({ minimize, maximize });
|
||||
this.roll({ minimize, maximize, async });
|
||||
}
|
||||
|
||||
// Apply modifiers
|
||||
|
||||
@@ -294,14 +294,6 @@ export class RollL5r5e extends Roll {
|
||||
return renderTemplate(chatOptions.template, chatData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the HTML for the ChatMessage which should be added to the log
|
||||
* @return {Promise<jQuery>}
|
||||
*/
|
||||
async getHTML() {
|
||||
console.log(" --------- getHTML");
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a Roll instance into a ChatMessage, displaying the roll result.
|
||||
* This function can either create the ChatMessage directly, or return the data object that will be used to create.
|
||||
|
||||
@@ -7,6 +7,14 @@ export class ItemL5r5e extends Item {
|
||||
return this.data.data.items || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the linked Actor instance if any (current or embed)
|
||||
* @return {Actor|null}
|
||||
*/
|
||||
get actor() {
|
||||
return super.actor || game.actors.get(this.data.data.parent_id?.actor_id) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new entity using provided input data
|
||||
* @override
|
||||
@@ -27,7 +35,7 @@ export class ItemL5r5e extends Item {
|
||||
*/
|
||||
async update(data = {}, context = {}) {
|
||||
// Regular
|
||||
if (!this.data.data.parentId) {
|
||||
if (!this.data.data.parent_id) {
|
||||
return super.update(data, context);
|
||||
}
|
||||
|
||||
@@ -67,7 +75,7 @@ export class ItemL5r5e extends Item {
|
||||
this.data.data.items = new Map();
|
||||
|
||||
itemsData.forEach((item) => {
|
||||
this.addEmbedItem(item, { save: false, newId: false });
|
||||
this.addEmbedItem(item, { save: false, newId: false, addBonusToActor: false });
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -75,10 +83,16 @@ export class ItemL5r5e extends Item {
|
||||
// ***** parent ids management *****
|
||||
/**
|
||||
* Return a string with idemId + actorId if any
|
||||
* @return {string} itemId|actor
|
||||
* @return {{item_id: (string|null), actor_id?: (string|null)}}
|
||||
*/
|
||||
getParentsIds() {
|
||||
return this.id + (this.actor?.data?._id ? `|${this.actor.data._id}` : "");
|
||||
const parent = {
|
||||
item_id: this.id,
|
||||
};
|
||||
if (this.actor?.data?._id) {
|
||||
parent.actor_id = this.actor.data._id;
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,17 +100,18 @@ export class ItemL5r5e extends Item {
|
||||
* @return {ItemL5r5e|null}
|
||||
*/
|
||||
getItemFromParentId() {
|
||||
const parentIds = this.data.data.parent_id;
|
||||
let parentItem;
|
||||
let [parentItemId, parentActorId] = this.data.data.parentId.split("|");
|
||||
|
||||
if (parentActorId) {
|
||||
if (parentIds?.actor_id) {
|
||||
// Actor item object
|
||||
const parentActor = parentActorId ? game.actors.get(parentActorId) : null;
|
||||
parentItem = parentActor?.items.get(parentItemId);
|
||||
} else {
|
||||
const parentActor = parentIds.actor_id ? game.actors.get(parentIds.actor_id) : null;
|
||||
parentItem = parentActor?.items.get(parentIds.item_id);
|
||||
} else if (parentIds?.item_id) {
|
||||
// World Object
|
||||
parentItem = game.items.get(parentItemId);
|
||||
parentItem = game.items.get(parentIds.item_id);
|
||||
}
|
||||
|
||||
return parentItem;
|
||||
}
|
||||
|
||||
@@ -115,9 +130,10 @@ export class ItemL5r5e extends 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
|
||||
* @param {boolean} addBonusToActor if we update the actor bonus for advancements
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async addEmbedItem(item, { save = true, newId = true } = {}) {
|
||||
async addEmbedItem(item, { save = true, newId = true, addBonusToActor = true } = {}) {
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
@@ -133,14 +149,17 @@ export class ItemL5r5e extends Item {
|
||||
}
|
||||
|
||||
// Tag parent (flags won't work as we have no id in db)
|
||||
item.data.data.parentId = this.getParentsIds();
|
||||
item.data.data.parent_id = 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);
|
||||
// Add bonus to actor
|
||||
if (addBonusToActor) {
|
||||
const actor = this.actor;
|
||||
if (item instanceof Item && actor instanceof Actor) {
|
||||
actor.addBonus(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (save) {
|
||||
@@ -155,23 +174,28 @@ export class ItemL5r5e extends Item {
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async updateEmbedItem(item, { save = true } = {}) {
|
||||
await this.addEmbedItem(item, { save, newId: false });
|
||||
await this.addEmbedItem(item, { save, newId: false, addBonusToActor: false });
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the Embed Item and clear the actor bonus if any
|
||||
* @param {ItemL5r5e} item Object to add
|
||||
* @param id Item id
|
||||
* @param {boolean} save if we save in db or not (used internally)
|
||||
* @param {boolean} removeBonusFromActor if we update the actor bonus for advancements
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async deleteEmbedItem(id, { save = true } = {}) {
|
||||
async deleteEmbedItem(id, { save = true, removeBonusFromActor = 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 bonus from actor
|
||||
if (removeBonusFromActor) {
|
||||
const actor = this.actor;
|
||||
const item = this.data.data.items.get(id);
|
||||
if (item instanceof Item && actor instanceof Actor) {
|
||||
actor.removeBonus(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the embed item
|
||||
|
||||
@@ -7,7 +7,7 @@ export class AdvancementSheetL5r5e extends ItemSheetL5r5e {
|
||||
/**
|
||||
* Sub Types of advancements
|
||||
*/
|
||||
static types = ["ring", "skill"]; // "peculiarity" and "technique" have theirs own xp count
|
||||
static types = ["ring", "skill"]; // others have theirs own xp count
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
@@ -73,47 +73,55 @@ export class AdvancementSheetL5r5e extends ItemSheetL5r5e {
|
||||
|
||||
// Modify image to reflect choice
|
||||
if (newChoice.ring) {
|
||||
name = game.i18n.localize(`l5r5e.rings.${newChoice.ring}`) + "+1";
|
||||
img = `systems/l5r5e/assets/icons/rings/${newChoice.ring}.svg`;
|
||||
} else if (newChoice.skill) {
|
||||
name =
|
||||
game.i18n.localize(`l5r5e.skills.${CONFIG.l5r5e.skills.get(newChoice.skill)}.${newChoice.skill}`) +
|
||||
"+1";
|
||||
img = `systems/l5r5e/assets/dices/default/skill_blank.svg`;
|
||||
}
|
||||
|
||||
// Object embed in actor ?
|
||||
if (this.actor) {
|
||||
const actor = duplicate(this.actor.data.data);
|
||||
const actor = this.document.actor;
|
||||
if (actor) {
|
||||
const actorData = foundry.utils.duplicate(actor.data.data);
|
||||
let skillCatId = null;
|
||||
|
||||
// Old choices
|
||||
if (oldChoice.ring) {
|
||||
actor.rings[oldChoice.ring] = Math.max(1, actor.rings[oldChoice.ring] - 1);
|
||||
actorData.rings[oldChoice.ring] = Math.max(1, actorData.rings[oldChoice.ring] - 1);
|
||||
}
|
||||
if (oldChoice.skill) {
|
||||
skillCatId = CONFIG.l5r5e.skills.get(oldChoice.skill);
|
||||
actor.skills[skillCatId][oldChoice.skill] = Math.max(0, actor.skills[skillCatId][oldChoice.skill] - 1);
|
||||
actorData.skills[skillCatId][oldChoice.skill] = Math.max(
|
||||
0,
|
||||
actorData.skills[skillCatId][oldChoice.skill] - 1
|
||||
);
|
||||
}
|
||||
|
||||
// new choices
|
||||
if (newChoice.ring) {
|
||||
actor.rings[newChoice.ring] = actor.rings[newChoice.ring] + 1;
|
||||
xp_used = actor.rings[newChoice.ring] * CONFIG.l5r5e.xp.ringCostMultiplier;
|
||||
actorData.rings[newChoice.ring] = actorData.rings[newChoice.ring] + 1;
|
||||
xp_used = actorData.rings[newChoice.ring] * CONFIG.l5r5e.xp.ringCostMultiplier;
|
||||
name =
|
||||
game.i18n.localize(`l5r5e.rings.${newChoice.ring}`) +
|
||||
` +1 (${actor.rings[newChoice.ring] - 1} -> ${actor.rings[newChoice.ring]})`;
|
||||
` +1 (${actorData.rings[newChoice.ring] - 1} -> ${actorData.rings[newChoice.ring]})`;
|
||||
}
|
||||
if (newChoice.skill) {
|
||||
skillCatId = CONFIG.l5r5e.skills.get(newChoice.skill);
|
||||
actor.skills[skillCatId][newChoice.skill] = actor.skills[skillCatId][newChoice.skill] + 1;
|
||||
xp_used = actor.skills[skillCatId][newChoice.skill] * CONFIG.l5r5e.xp.skillCostMultiplier;
|
||||
actorData.skills[skillCatId][newChoice.skill] = actorData.skills[skillCatId][newChoice.skill] + 1;
|
||||
xp_used = actorData.skills[skillCatId][newChoice.skill] * CONFIG.l5r5e.xp.skillCostMultiplier;
|
||||
name =
|
||||
game.i18n.localize(`l5r5e.skills.${skillCatId}.${newChoice.skill}`) +
|
||||
` +1 (${actor.skills[skillCatId][newChoice.skill] - 1} -> ${
|
||||
actor.skills[skillCatId][newChoice.skill]
|
||||
` +1 (${actorData.skills[skillCatId][newChoice.skill] - 1} -> ${
|
||||
actorData.skills[skillCatId][newChoice.skill]
|
||||
})`;
|
||||
}
|
||||
|
||||
// Update Actor
|
||||
await this.actor.update({
|
||||
data: diffObject(this.actor.data.data, actor),
|
||||
await actor.update({
|
||||
data: foundry.utils.diffObject(actor.data.data, actorData),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,6 @@ export class ItemPatternSheetL5r5e extends ItemSheetL5r5e {
|
||||
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);
|
||||
|
||||
|
||||
@@ -256,6 +256,23 @@ export class ItemSheetL5r5e extends ItemSheet {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const itemId = $(event.currentTarget).data("item-id");
|
||||
this.document.deleteEmbedItem(itemId);
|
||||
const item = this.document.getEmbedItem(itemId);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
const callback = async () => {
|
||||
this.document.deleteEmbedItem(itemId);
|
||||
};
|
||||
|
||||
// Holing Ctrl = without confirm
|
||||
if (event.ctrlKey) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
game.l5r5e.HelpersL5r5e.confirmDeleteDialog(
|
||||
game.i18n.format("l5r5e.global.delete_confirm", { name: item.name }),
|
||||
callback
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,14 +21,15 @@ export class TitleSheetL5r5e extends ItemSheetL5r5e {
|
||||
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
|
||||
// Automatically compute the xp cost
|
||||
sheetData.data.data.xp_used = sheetData.data.embedItemsList.reduce(
|
||||
(acc, item) => acc + (+item.data.xp_used || 0),
|
||||
0
|
||||
);
|
||||
|
||||
return sheetData;
|
||||
}
|
||||
|
||||
@@ -63,17 +64,19 @@ export class TitleSheetL5r5e extends ItemSheetL5r5e {
|
||||
|
||||
// Check item type and subtype
|
||||
let item = await game.l5r5e.HelpersL5r5e.getDragnDropTargetObject(event);
|
||||
if (!item || (item.documentName !== "Item" && !["technique", "advancement"].includes(item.data.type))) {
|
||||
if (!item || item.documentName !== "Item" || !["technique", "advancement"].includes(item.data.type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = item.data.toJSON();
|
||||
const data = item.data.toObject(false);
|
||||
|
||||
console.log("------ data", data); // todo tmp
|
||||
// Check xp for techs
|
||||
if (item.data.type === "technique") {
|
||||
data.data.xp_cost = data.data.xp_cost > 0 ? data.data.xp_cost : CONFIG.l5r5e.xp.techniqueCost;
|
||||
data.data.xp_used = data.data.xp_cost;
|
||||
}
|
||||
|
||||
this.document.addEmbedItem(data);
|
||||
|
||||
console.log(this.document); // todo tmp
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,16 +96,4 @@ export class TitleSheetL5r5e extends ItemSheetL5r5e {
|
||||
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);
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
*/
|
||||
export class MigrationL5r5e {
|
||||
/**
|
||||
* Version needed for migration stuff to trigger
|
||||
* Minimum Version needed for migration stuff to trigger
|
||||
* @type {string}
|
||||
*/
|
||||
static NEEDED_VERSION = "1.1.0";
|
||||
static NEEDED_VERSION = "1.3.0";
|
||||
|
||||
/**
|
||||
* Return true if the current world need some updates
|
||||
@@ -14,7 +14,7 @@ export class MigrationL5r5e {
|
||||
*/
|
||||
static needUpdate() {
|
||||
const currentVersion = game.settings.get("l5r5e", "systemMigrationVersion");
|
||||
return currentVersion && isNewerVersion(MigrationL5r5e.NEEDED_VERSION, currentVersion);
|
||||
return currentVersion && foundry.utils.isNewerVersion(MigrationL5r5e.NEEDED_VERSION, currentVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,6 +26,7 @@ export class MigrationL5r5e {
|
||||
return;
|
||||
}
|
||||
|
||||
// Warn the users
|
||||
ui.notifications.info(
|
||||
`Applying L5R5e System Migration for version ${game.system.data.version}.` +
|
||||
` Please be patient and do not close your game or shut down your server.`,
|
||||
@@ -33,56 +34,53 @@ export class MigrationL5r5e {
|
||||
);
|
||||
|
||||
// Migrate World Actors
|
||||
for (let a of game.actors.contents) {
|
||||
for (let actor of game.actors.contents) {
|
||||
try {
|
||||
const updateData = MigrationL5r5e._migrateActorData(a.data);
|
||||
if (!isObjectEmpty(updateData)) {
|
||||
console.log(`Migrating Actor entity ${a.name}`);
|
||||
await a.update(updateData, { enforceTypes: false }); // TODO use Actor.updateDocuments(data, context) for multiple actors
|
||||
const updateData = MigrationL5r5e._migrateActorData(actor.data);
|
||||
if (!foundry.utils.isObjectEmpty(updateData)) {
|
||||
console.log(`L5R5E | Migrating Actor entity ${actor.name}`);
|
||||
await actor.update(updateData);
|
||||
}
|
||||
} catch (err) {
|
||||
err.message = `Failed L5R5e system migration for Actor ${a.name}: ${err.message}`;
|
||||
err.message = `L5R5E | Failed L5R5e system migration for Actor ${actor.name}: ${err.message}`;
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate World Items
|
||||
for (let i of game.items.contents) {
|
||||
for (let item of game.items.contents) {
|
||||
try {
|
||||
const updateData = MigrationL5r5e._migrateItemData(i.data);
|
||||
if (!isObjectEmpty(updateData)) {
|
||||
console.log(`Migrating Item entity ${i.name}`);
|
||||
await i.update(updateData, { enforceTypes: false }); // TODO use Item.updateDocuments(data, context) for multiple actors
|
||||
const updateData = MigrationL5r5e._migrateItemData(item.data);
|
||||
if (!foundry.utils.isObjectEmpty(updateData)) {
|
||||
console.log(`L5R5E | Migrating Item entity ${item.name}`);
|
||||
await item.update(updateData);
|
||||
}
|
||||
} catch (err) {
|
||||
err.message = `Failed L5R5e system migration for Item ${i.name}: ${err.message}`;
|
||||
err.message = `L5R5E | Failed L5R5e system migration for Item ${item.name}: ${err.message}`;
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate Actor Override Tokens
|
||||
for (let s of game.scenes.contents) {
|
||||
for (let scene of game.scenes.contents) {
|
||||
try {
|
||||
const updateData = MigrationL5r5e._migrateSceneData(s.data);
|
||||
if (!isObjectEmpty(updateData)) {
|
||||
console.log(`Migrating Scene entity ${s.name}`);
|
||||
await s.update(updateData, { enforceTypes: false }); // TODO use Scene.updateDocuments(data, context) for multiple actors
|
||||
const updateData = MigrationL5r5e._migrateSceneData(scene.data);
|
||||
if (!foundry.utils.isObjectEmpty(updateData)) {
|
||||
console.log(`L5R5E | Migrating Scene entity ${scene.name}`);
|
||||
await scene.update(updateData);
|
||||
}
|
||||
} catch (err) {
|
||||
err.message = `Failed L5R5e system migration for Scene ${s.name}: ${err.message}`;
|
||||
err.message = `L5R5E | Failed L5R5e system migration for Scene ${scene.name}: ${err.message}`;
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate World Compendium Packs
|
||||
for (let p of game.packs) {
|
||||
if (p.metadata.package !== "world") {
|
||||
for (let pack of game.packs) {
|
||||
if (pack.metadata.package !== "world" || !["Actor", "Item", "Scene"].includes(pack.metadata.entity)) {
|
||||
continue;
|
||||
}
|
||||
if (!["Actor", "Item", "Scene"].includes(p.metadata.entity)) {
|
||||
continue;
|
||||
}
|
||||
await MigrationL5r5e._migrateCompendium(p);
|
||||
await MigrationL5r5e._migrateCompendium(pack);
|
||||
}
|
||||
|
||||
// Set the migration as complete
|
||||
@@ -94,7 +92,7 @@ export class MigrationL5r5e {
|
||||
|
||||
/**
|
||||
* Apply migration rules to all Entities within a single Compendium pack
|
||||
* @param pack
|
||||
* @param {Compendium} pack
|
||||
* @return {Promise}
|
||||
*/
|
||||
static async _migrateCompendium(pack) {
|
||||
@@ -103,18 +101,20 @@ export class MigrationL5r5e {
|
||||
return;
|
||||
}
|
||||
|
||||
// Unlock the pack for editing
|
||||
const wasLocked = pack.locked;
|
||||
await pack.configure({ locked: false });
|
||||
try {
|
||||
// Unlock the pack for editing
|
||||
await pack.configure({ locked: false });
|
||||
|
||||
// Begin by requesting server-side data model migration and get the migrated content
|
||||
await pack.migrate();
|
||||
const content = await pack.getContent();
|
||||
// Begin by requesting server-side data model migration and get the migrated content
|
||||
await pack.migrate();
|
||||
const documents = await pack.getDocuments();
|
||||
|
||||
// Iterate over compendium entries - applying fine-tuned migration functions
|
||||
const updateDatasList = [];
|
||||
for (let ent of documents) {
|
||||
let updateData = {};
|
||||
|
||||
// Iterate over compendium entries - applying fine-tuned migration functions
|
||||
for (let ent of content) {
|
||||
let updateData = {};
|
||||
try {
|
||||
switch (entity) {
|
||||
case "Actor":
|
||||
updateData = MigrationL5r5e._migrateActorData(ent.data);
|
||||
@@ -126,24 +126,30 @@ export class MigrationL5r5e {
|
||||
updateData = MigrationL5r5e._migrateSceneData(ent.data);
|
||||
break;
|
||||
}
|
||||
if (isObjectEmpty(updateData)) {
|
||||
if (foundry.utils.isObjectEmpty(updateData)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Save the entry, if data was changed
|
||||
updateData["_id"] = ent._id;
|
||||
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
|
||||
err.message = `Failed L5R5e system migration for entity ${ent.name} in pack ${pack.collection}: ${err.message}`;
|
||||
console.error(err);
|
||||
// Add the entry, if data was changed
|
||||
updateData["_id"] = ent.data._id;
|
||||
updateDatasList.push(updateData);
|
||||
|
||||
console.log(`L5R5E | Migrating ${entity} entity ${ent.name} in Compendium ${pack.collection}`);
|
||||
}
|
||||
|
||||
// Save the modified entries
|
||||
if (updateDatasList.length > 0) {
|
||||
await pack.documentClass.updateDocuments(updateDatasList, { pack: pack.collection });
|
||||
}
|
||||
} catch (err) {
|
||||
// Handle migration failures
|
||||
err.message = `L5R5E | Failed system migration for entities ${entity} in pack ${pack.collection}: ${err.message}`;
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
// Apply the original locked status for the pack
|
||||
pack.configure({ locked: wasLocked });
|
||||
console.log(`Migrated all ${entity} contents from Compendium ${pack.collection}`);
|
||||
console.log(`L5R5E | Migrated all ${entity} contents from Compendium ${pack.collection}`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,7 +159,7 @@ export class MigrationL5r5e {
|
||||
* @return {Object} The updateData to apply
|
||||
*/
|
||||
static _migrateSceneData(scene) {
|
||||
const tokens = duplicate(scene.tokens);
|
||||
const tokens = foundry.utils.duplicate(scene.tokens);
|
||||
return {
|
||||
tokens: tokens.map((t) => {
|
||||
if (!t.actorId || t.actorLink || !t.actorData.data) {
|
||||
@@ -183,8 +189,6 @@ export class MigrationL5r5e {
|
||||
const updateData = {};
|
||||
const actorData = actor.data;
|
||||
|
||||
console.log(actorData); // TODO TMP data.data ? à vérifier
|
||||
|
||||
// ***** Start of 1.1.0 *****
|
||||
// Add "Prepared" in actor
|
||||
if (actorData.prepared === undefined) {
|
||||
@@ -211,6 +215,10 @@ export class MigrationL5r5e {
|
||||
actorData.rings_affinities.strength.value;
|
||||
updateData["data.rings_affinities." + actorData.rings_affinities.weakness.ring] =
|
||||
actorData.rings_affinities.weakness.value;
|
||||
|
||||
// Delete old keys : not working :'(
|
||||
updateData["-=data.rings_affinities.strength"] = null;
|
||||
updateData["-=data.rings_affinities.weakness"] = null;
|
||||
}
|
||||
// ***** End of 1.3.0 *****
|
||||
|
||||
@@ -224,7 +232,7 @@ export class MigrationL5r5e {
|
||||
*/
|
||||
static cleanActorData(actorData) {
|
||||
const model = game.system.model.Actor[actorData.type];
|
||||
actorData.data = filterObject(actorData.data, model);
|
||||
actorData.data = foundry.utils.filterObject(actorData.data, model);
|
||||
return actorData;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user