feat: update for v10

This commit is contained in:
Johannes Loher 2022-11-21 03:00:46 +01:00
parent 6277e27056
commit f25b46a226
63 changed files with 41349 additions and 24332 deletions

4
.gitignore vendored
View file

@ -34,5 +34,5 @@ junit.xml
.pnp.* .pnp.*
# foundry # foundry
client /client
common /common

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -4,175 +4,263 @@
"name": "Gormanische Schrift", "name": "Gormanische Schrift",
"type": "alphabet", "type": "alphabet",
"img": "icons/svg/book.svg", "img": "icons/svg/book.svg",
"data": {
"description": ""
},
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 0, "sort": 0,
"permission": { "flags": {},
"system": {
"description": ""
},
"ownership": {
"default": 0 "default": 0
}, },
"flags": {} "_stats": {
"systemId": "ds4",
"systemVersion": "1.18.1",
"coreVersion": "10.290",
"createdTime": 1668995342357,
"modifiedTime": 1668995456385,
"lastModifiedBy": "DS4BuildSystem00"
}
}, },
{ {
"_id": "GQNpFENXcjJGeYr2", "_id": "GQNpFENXcjJGeYr2",
"name": "Freiwort", "name": "Freiwort",
"type": "language", "type": "language",
"img": "systems/ds4/assets/icons/game-icons/lorc/conversation.svg", "img": "systems/ds4/assets/icons/game-icons/lorc/conversation.svg",
"data": {
"description": "<p>Freiwort ist die Gemeinsprache der Freien Lande.</p>"
},
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 0, "sort": 0,
"permission": { "flags": {},
"system": {
"description": "<p>Freiwort ist die Gemeinsprache der Freien Lande.</p>"
},
"ownership": {
"default": 0 "default": 0
}, },
"flags": {} "_stats": {
"systemId": "ds4",
"systemVersion": "1.18.1",
"coreVersion": "10.290",
"createdTime": 1668995342358,
"modifiedTime": 1668995456386,
"lastModifiedBy": "DS4BuildSystem00"
}
}, },
{ {
"_id": "O1U9jd0yJoydHwT8", "_id": "O1U9jd0yJoydHwT8",
"name": "Zasarische Schrift", "name": "Zasarische Schrift",
"type": "alphabet", "type": "alphabet",
"img": "icons/svg/book.svg", "img": "icons/svg/book.svg",
"data": {
"description": ""
},
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 0, "sort": 0,
"permission": { "flags": {},
"system": {
"description": ""
},
"ownership": {
"default": 0 "default": 0
}, },
"flags": {} "_stats": {
"systemId": "ds4",
"systemVersion": "1.18.1",
"coreVersion": "10.290",
"createdTime": 1668995342359,
"modifiedTime": 1668995456388,
"lastModifiedBy": "DS4BuildSystem00"
}
}, },
{ {
"_id": "PzkVTViII6ungWyp", "_id": "PzkVTViII6ungWyp",
"name": "Zwergisch", "name": "Zwergisch",
"type": "language", "type": "language",
"img": "systems/ds4/assets/icons/game-icons/lorc/conversation.svg", "img": "systems/ds4/assets/icons/game-icons/lorc/conversation.svg",
"data": {
"description": ""
},
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 0, "sort": 0,
"permission": { "flags": {},
"system": {
"description": ""
},
"ownership": {
"default": 0 "default": 0
}, },
"flags": {} "_stats": {
"systemId": "ds4",
"systemVersion": "1.18.1",
"coreVersion": "10.290",
"createdTime": 1668995342360,
"modifiedTime": 1668995456389,
"lastModifiedBy": "DS4BuildSystem00"
}
}, },
{ {
"_id": "josgKzD9UmDOvTup", "_id": "josgKzD9UmDOvTup",
"name": "Ornamentschrift", "name": "Ornamentschrift",
"type": "alphabet", "type": "alphabet",
"img": "icons/svg/book.svg", "img": "icons/svg/book.svg",
"data": {
"description": ""
},
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 0, "sort": 0,
"permission": { "flags": {},
"system": {
"description": ""
},
"ownership": {
"default": 0 "default": 0
}, },
"flags": {} "_stats": {
"systemId": "ds4",
"systemVersion": "1.18.1",
"coreVersion": "10.290",
"createdTime": 1668995342361,
"modifiedTime": 1668995456390,
"lastModifiedBy": "DS4BuildSystem00"
}
}, },
{ {
"_id": "k8FSxBda9CoLOJqZ", "_id": "k8FSxBda9CoLOJqZ",
"name": "Kaitanische Schrift", "name": "Kaitanische Schrift",
"type": "alphabet", "type": "alphabet",
"img": "icons/svg/book.svg", "img": "icons/svg/book.svg",
"data": {
"description": ""
},
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 0, "sort": 0,
"permission": { "flags": {},
"system": {
"description": ""
},
"ownership": {
"default": 0 "default": 0
}, },
"flags": {} "_stats": {
"systemId": "ds4",
"systemVersion": "1.18.1",
"coreVersion": "10.290",
"createdTime": 1668995342362,
"modifiedTime": 1668995456391,
"lastModifiedBy": "DS4BuildSystem00"
}
}, },
{ {
"_id": "n2Nbg0ttFzcMxp7T", "_id": "n2Nbg0ttFzcMxp7T",
"name": "Keilschrift", "name": "Keilschrift",
"type": "alphabet", "type": "alphabet",
"img": "icons/svg/book.svg", "img": "icons/svg/book.svg",
"data": {
"description": ""
},
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 0, "sort": 0,
"permission": { "flags": {},
"system": {
"description": ""
},
"ownership": {
"default": 0 "default": 0
}, },
"flags": {} "_stats": {
"systemId": "ds4",
"systemVersion": "1.18.1",
"coreVersion": "10.290",
"createdTime": 1668995342364,
"modifiedTime": 1668995456392,
"lastModifiedBy": "DS4BuildSystem00"
}
}, },
{ {
"_id": "n6KU1XIzbPWups0D", "_id": "n6KU1XIzbPWups0D",
"name": "Kaitanisch", "name": "Kaitanisch",
"type": "language", "type": "language",
"img": "systems/ds4/assets/icons/game-icons/lorc/conversation.svg", "img": "systems/ds4/assets/icons/game-icons/lorc/conversation.svg",
"data": {
"description": ""
},
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 0, "sort": 0,
"permission": { "flags": {},
"system": {
"description": ""
},
"ownership": {
"default": 0 "default": 0
}, },
"flags": {} "_stats": {
"systemId": "ds4",
"systemVersion": "1.18.1",
"coreVersion": "10.290",
"createdTime": 1668995342365,
"modifiedTime": 1668995456393,
"lastModifiedBy": "DS4BuildSystem00"
}
}, },
{ {
"_id": "usEWD48iYnMHO3Ty", "_id": "usEWD48iYnMHO3Ty",
"name": "Zasarisch", "name": "Zasarisch",
"type": "language", "type": "language",
"img": "systems/ds4/assets/icons/game-icons/lorc/conversation.svg", "img": "systems/ds4/assets/icons/game-icons/lorc/conversation.svg",
"data": {
"description": ""
},
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 0, "sort": 0,
"permission": { "flags": {},
"system": {
"description": ""
},
"ownership": {
"default": 0 "default": 0
}, },
"flags": {} "_stats": {
"systemId": "ds4",
"systemVersion": "1.18.1",
"coreVersion": "10.290",
"createdTime": 1668995342366,
"modifiedTime": 1668995456394,
"lastModifiedBy": "DS4BuildSystem00"
}
}, },
{ {
"_id": "xpvHuSywc8lJa2UN", "_id": "xpvHuSywc8lJa2UN",
"name": "Elfisch", "name": "Elfisch",
"type": "language", "type": "language",
"img": "systems/ds4/assets/icons/game-icons/lorc/conversation.svg", "img": "systems/ds4/assets/icons/game-icons/lorc/conversation.svg",
"data": {
"description": ""
},
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 0, "sort": 0,
"permission": { "flags": {},
"system": {
"description": ""
},
"ownership": {
"default": 0 "default": 0
}, },
"flags": {} "_stats": {
"systemId": "ds4",
"systemVersion": "1.18.1",
"coreVersion": "10.290",
"createdTime": 1668995342367,
"modifiedTime": 1668995456395,
"lastModifiedBy": "DS4BuildSystem00"
}
}, },
{ {
"_id": "ylqXcZHRbIBeV20Z", "_id": "ylqXcZHRbIBeV20Z",
"name": "Ahnenrunen", "name": "Ahnenrunen",
"type": "alphabet", "type": "alphabet",
"img": "icons/svg/book.svg", "img": "icons/svg/book.svg",
"data": {
"description": ""
},
"effects": [], "effects": [],
"folder": null, "folder": null,
"sort": 0, "sort": 0,
"permission": { "flags": {},
"system": {
"description": ""
},
"ownership": {
"default": 0 "default": 0
}, },
"flags": {} "_stats": {
"systemId": "ds4",
"systemVersion": "1.18.1",
"coreVersion": "10.290",
"createdTime": 1668995342375,
"modifiedTime": 1668995456396,
"lastModifiedBy": "DS4BuildSystem00"
}
} }
] ]

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -37,14 +37,14 @@ export class DS4ActorSheet extends ActorSheet {
get template() { get template() {
const basePath = "systems/ds4/templates/sheets/actor"; const basePath = "systems/ds4/templates/sheets/actor";
if (!getGame().user?.isGM && this.actor.limited) return `${basePath}/limited-sheet.hbs`; if (!getGame().user?.isGM && this.actor.limited) return `${basePath}/limited-sheet.hbs`;
return `${basePath}/${this.actor.data.type}-sheet.hbs`; return `${basePath}/${this.actor.type}-sheet.hbs`;
} }
/** @override */ /** @override */
async getData(options) { async getData(options = {}) {
const itemsByType = Object.fromEntries( const itemsByType = Object.fromEntries(
Object.entries(this.actor.itemTypes).map(([itemType, items]) => { Object.entries(this.actor.itemTypes).map(([itemType, items]) => {
return [itemType, items.map((item) => item.data).sort((a, b) => (a.sort || 0) - (b.sort || 0))]; return [itemType, [...items].sort((a, b) => (a.sort || 0) - (b.sort || 0))];
}), }),
); );
@ -53,35 +53,39 @@ export class DS4ActorSheet extends ActorSheet {
...effect.toObject(), ...effect.toObject(),
sourceName: await effect.getCurrentSourceName(), sourceName: await effect.getCurrentSourceName(),
factor: effect.factor, factor: effect.factor,
isEffectivelyEnabled: !effect.data.disabled && !effect.isSurpressed, isEffectivelyEnabled: !effect.disabled && !effect.isSurpressed,
}; };
}); });
const enrichedEffects = await Promise.all(enrichedEffectPromises); const enrichedEffects = await Promise.all(enrichedEffectPromises);
const data = { const context = {
...this.addTooltipsToData(await super.getData(options)), ...this.addTooltipsToData(await super.getData(options)),
config: DS4, config: DS4,
itemsByType, itemsByType,
enrichedEffects, enrichedEffects,
settings: getDS4Settings(), settings: getDS4Settings(),
}; };
return data; return context;
} }
/** /**
* Adds tooltips to the attributes, traits, and combatValues of the actor data of the given {@link ActorSheet.Data}. * Adds tooltips to the attributes, traits, and combatValues of the given context object.
* @param {object} data * @param {object} context
* @protected * @protected
*/ */
addTooltipsToData(data) { addTooltipsToData(context) {
const valueGroups = [data.data.data.attributes, data.data.data.traits, data.data.data.combatValues]; const valueGroups = [
context.data.system.attributes,
context.data.system.traits,
context.data.system.combatValues,
];
valueGroups.forEach((valueGroup) => { valueGroups.forEach((valueGroup) => {
Object.values(valueGroup).forEach((attribute) => { Object.values(valueGroup).forEach((attribute) => {
attribute.tooltip = this.getTooltipForValue(attribute); attribute.tooltip = this.getTooltipForValue(attribute);
}); });
}); });
return data; return context;
} }
/** /**
@ -154,13 +158,9 @@ export class DS4ActorSheet extends ActorSheet {
* @protected * @protected
*/ */
onCreateItem(event) { onCreateItem(event) {
const { type, ...data } = foundry.utils.deepClone(event.currentTarget.dataset); const { type } = foundry.utils.deepClone(event.currentTarget.dataset);
const name = getGame().i18n.localize(`DS4.New${type.capitalize()}Name`); const name = getGame().i18n.localize(`DS4.New${type.capitalize()}Name`);
const itemData = { const itemData = { name, type };
name: name,
type: type,
data: data,
};
Item.create(itemData, { parent: this.actor, pack: this.actor.pack ?? undefined }); Item.create(itemData, { parent: this.actor, pack: this.actor.pack ?? undefined });
} }
@ -394,24 +394,25 @@ export class DS4ActorSheet extends ActorSheet {
const dataPath = target.dataset["dataPath"]; const dataPath = target.dataset["dataPath"];
enforce(dataPath !== undefined, `Could not find property 'dataPath' in the dataset of ${target}`); enforce(dataPath !== undefined, `Could not find property 'dataPath' in the dataset of ${target}`);
const dataPath2 = target.dataset["dataPath2"]; const dataPath2 = target.dataset["dataPath2"];
/** @type {import("../../documents/item/item").DS4Item[]}*/
const items = this.actor.items.filter((item) => item.type === type); const items = this.actor.items.filter((item) => item.type === type);
items.sort((a, b) => a.data.sort - b.data.sort); items.sort((a, b) => a.sort - b.sort);
/** /**
* @param {boolean} invert Whether or not to inverse the sort order * @param {boolean} invert Whether or not to inverse the sort order
* @returns {(a: import("../../documents/item/item").DS4Item, b: import("../../documents/item/item").DS4Item) => number} A function for sorting items * @returns {(a: import("../../documents/item/item").DS4Item, b: import("../../documents/item/item").DS4Item) => number} A function for sorting items
*/ */
const sortFunction = (invert) => (a, b) => { const sortFunction = (invert) => (a, b) => {
const propertyA = getProperty(a.data, dataPath); const propertyA = getProperty(a, dataPath);
const propertyB = getProperty(b.data, dataPath); const propertyB = getProperty(b, dataPath);
const comparison = const comparison =
typeof propertyA === "string" || typeof propertyB === "string" typeof propertyA === "string" || typeof propertyB === "string"
? compareAsStrings(propertyA, propertyB, invert) ? compareAsStrings(propertyA, propertyB, invert)
: compareAsNumbers(propertyA, propertyB, invert); : compareAsNumbers(propertyA, propertyB, invert);
if (comparison === 0 && dataPath2 !== undefined) { if (comparison === 0 && dataPath2 !== undefined) {
const propertyA = getProperty(a.data, dataPath); const propertyA = getProperty(a, dataPath);
const propertyB = getProperty(b.data, dataPath); const propertyB = getProperty(b, dataPath);
return typeof propertyA === "string" || typeof propertyB === "string" return typeof propertyA === "string" || typeof propertyB === "string"
? compareAsStrings(propertyA, propertyB, invert) ? compareAsStrings(propertyA, propertyB, invert)
: compareAsNumbers(propertyA, propertyB, invert); : compareAsNumbers(propertyA, propertyB, invert);
@ -441,14 +442,14 @@ export class DS4ActorSheet extends ActorSheet {
* @override * @override
*/ */
async _onDropItem(event, data) { async _onDropItem(event, data) {
const item = await Item.fromDropData(data); const item = await Item.implementation.fromDropData(data);
if (item && !this.actor.canOwnItemType(item.data.type)) { if (item && !this.actor.canOwnItemType(item.type)) {
notifications.warn( notifications.warn(
getGame().i18n.format("DS4.WarningActorCannotOwnItem", { getGame().i18n.format("DS4.WarningActorCannotOwnItem", {
actorName: this.actor.name, actorName: this.actor.name,
actorType: this.actor.data.type, actorType: this.actor.type,
itemName: item.name, itemName: item.name,
itemType: item.data.type, itemType: item.type,
}), }),
); );
return false; return false;

View file

@ -13,4 +13,13 @@ export class DS4CharacterActorSheet extends DS4ActorSheet {
classes: ["sheet", "ds4-actor-sheet", "ds4-character-sheet"], classes: ["sheet", "ds4-actor-sheet", "ds4-character-sheet"],
}); });
} }
/** @override */
async getData(options = {}) {
const context = await super.getData(options);
context.data.system.profile.biography = await TextEditor.enrichHTML(context.data.system.profile.biography, {
async: true,
});
return context;
}
} }

View file

@ -13,4 +13,14 @@ export class DS4CreatureActorSheet extends DS4ActorSheet {
classes: ["sheet", "ds4-actor-sheet", "ds4-creature-sheet"], classes: ["sheet", "ds4-actor-sheet", "ds4-creature-sheet"],
}); });
} }
/** @override */
async getData(options = {}) {
const context = await super.getData(options);
context.data.system.baseInfo.description = await TextEditor.enrichHTML(
context.data.system.baseInfo.description,
{ async: true },
);
return context;
}
} }

View file

@ -6,7 +6,6 @@
import { DS4 } from "../config"; import { DS4 } from "../config";
import { DS4ActiveEffect } from "../documents/active-effect"; import { DS4ActiveEffect } from "../documents/active-effect";
import { isDS4ItemDataTypePhysical } from "../documents/item/item-data-source-base";
import { notifications } from "../ui/notifications"; import { notifications } from "../ui/notifications";
import { enforce, getGame } from "../utils/utils"; import { enforce, getGame } from "../utils/utils";
import { disableOverriddenFields } from "./sheet-helpers"; import { disableOverriddenFields } from "./sheet-helpers";
@ -29,19 +28,22 @@ export class DS4ItemSheet extends ItemSheet {
/** @override */ /** @override */
get template() { get template() {
const basePath = "systems/ds4/templates/sheets/item"; const basePath = "systems/ds4/templates/sheets/item";
return `${basePath}/${this.item.data.type}-sheet.hbs`; return `${basePath}/${this.item.type}-sheet.hbs`;
} }
/** @override */ /** @override */
async getData() { async getData(options = {}) {
const data = { const superContext = await super.getData(options);
...(await super.getData()), superContext.data.system.description = await TextEditor.enrichHTML(superContext.data.system.description, {
async: true,
});
const context = {
...superContext,
config: DS4, config: DS4,
isOwned: this.item.isOwned, isOwned: this.item.isOwned,
actor: this.item.actor, actor: this.item.actor,
isPhysical: isDS4ItemDataTypePhysical(this.item.data.data),
}; };
return data; return context;
} }
/** @override */ /** @override */

View file

@ -56,7 +56,7 @@ export class DS4ActiveEffect extends ActiveEffect {
return; return;
} }
const itemIdRegex = /Item\.([a-zA-Z0-9]+)/; const itemIdRegex = /Item\.([a-zA-Z0-9]+)/;
const itemId = this.data.origin?.match(itemIdRegex)?.[1]; const itemId = this.origin?.match(itemIdRegex)?.[1];
if (!itemId) { if (!itemId) {
return; return;
} }
@ -73,7 +73,7 @@ export class DS4ActiveEffect extends ActiveEffect {
/** @override */ /** @override */
apply(document, change) { apply(document, change) {
change.value = Roll.replaceFormulaData(change.value, document.data); change.value = Roll.replaceFormulaData(change.value, document);
try { try {
change.value = DS4ActiveEffect.safeEval(change.value).toString(); change.value = DS4ActiveEffect.safeEval(change.value).toString();
} catch (e) { } catch (e) {
@ -101,16 +101,17 @@ export class DS4ActiveEffect extends ActiveEffect {
*/ */
async getSource() { async getSource() {
if (this.source === undefined) { if (this.source === undefined) {
this.source = this.data.origin !== undefined ? await fromUuid(this.data.origin) : null; this.source = this.origin != null ? await fromUuid(this.origin) : null;
} }
return this.source; return this.source;
} }
/** /**
* Create a new {@link DS4ActiveEffect} using default data. * Create a new {@link DS4ActiveEffect} using default values.
* *
* @param {import("./item/item").DS4Item | import("./actor/actor").DS4Actor} parent The parent of the effect. * @param {import("./item/item").DS4Item | import("./actor/actor").DS4Actor} parent The parent of the effect.
* @returns {Promise<DS4ActiveEffect | undefined>}A promise that resolved to the created effect or udifined of the creation was prevented. * @returns {Promise<DS4ActiveEffect | undefined>} A promise that resolved to the created effect or udifined of the
* creation was prevented.
*/ */
static async createDefault(parent) { static async createDefault(parent) {
const createData = { const createData = {
@ -169,23 +170,27 @@ export class DS4ActiveEffect extends ActiveEffect {
* @protected * @protected
*/ */
getFactoredChangesWithEffect(predicate = () => true) { getFactoredChangesWithEffect(predicate = () => true) {
if (this.data.disabled || this.isSurpressed) { if (this.disabled || this.isSurpressed) {
return []; return [];
} }
return this.data.changes.filter(predicate).flatMap((change) => { return this.changes.filter(predicate).flatMap((change) => {
change.priority = change.priority ?? change.mode * 10; change.priority = change.priority ?? change.mode * 10;
return Array(this.factor).fill({ effect: this, change }); return Array(this.factor).fill({ effect: this, change });
}); });
} }
} }
/**
* @typedef {foundry.data.ActiveEffectData["changes"][number]} EffectChangeData
*/
/** /**
* @typedef {object} EffectChangeDataWithEffect * @typedef {object} EffectChangeDataWithEffect
* @property {DS4ActiveEffect} effect * @property {DS4ActiveEffect} effect
* @property {EffectChangeData} change * @property {EffectChangeData} change
*/ */
/**
* @typedef {object} EffectChangeData
* @property {string} key The attribute path in the Actor or Item data which the change modifies
* @property {string} value The value of the change effect
* @property {number} mode The modification mode with which the change is applied
* @property {number} priority The priority level with which this change is applied
*/

View file

@ -17,7 +17,6 @@ import { isAttribute, isTrait } from "./actor-data-source-base";
export class DS4Actor extends Actor { export class DS4Actor extends Actor {
/** @override */ /** @override */
prepareData() { prepareData() {
this.data.reset();
this.prepareBaseData(); this.prepareBaseData();
this.prepareEmbeddedDocuments(); this.prepareEmbeddedDocuments();
this.prepareIntermediateData(); this.prepareIntermediateData();
@ -29,18 +28,16 @@ export class DS4Actor extends Actor {
/** @override */ /** @override */
prepareBaseData() { prepareBaseData() {
const data = this.data; this.system.rolling = {
data.data.rolling = {
minimumFumbleResult: 20, minimumFumbleResult: 20,
maximumCoupResult: 1, maximumCoupResult: 1,
}; };
const attributes = data.data.attributes; Object.values(this.system.attributes).forEach(
Object.values(attributes).forEach((attribute) => (attribute.total = attribute.base + attribute.mod)); (attribute) => (attribute.total = attribute.base + attribute.mod),
);
const traits = data.data.traits; Object.values(this.system.traits).forEach((trait) => (trait.total = trait.base + trait.mod));
Object.values(traits).forEach((trait) => (trait.total = trait.base + trait.mod));
} }
/** @override */ /** @override */
@ -54,26 +51,26 @@ export class DS4Actor extends Actor {
* applied to the Actor. * applied to the Actor.
*/ */
prepareIntermediateData() { prepareIntermediateData() {
this.data.data.armorValueSpellMalus = this.armorValueSpellMalusOfEquippedItems; this.system.armorValueSpellMalus = this.armorValueSpellMalusOfEquippedItems;
} }
/** /**
* The effects that should be applioed to this actor. * The effects that should be applioed to this actor.
* @type {this["effects"]} * @type {import("../active-effect").DS4ActiveEffect[]}
* @protected * @protected
*/ */
get actorEffects() { get actorEffects() {
return this.effects.filter((effect) => !effect.data.flags.ds4?.itemEffectConfig?.applyToItems); return this.effects.filter((effect) => !effect.flags.ds4?.itemEffectConfig?.applyToItems);
} }
/** /**
* Get the effects of this actor that should be applied to the given item. * Get the effects of this actor that should be applied to the given item.
* @param {import("../item/item").DS4Item} item The item for which to get effects * @param {import("../item/item").DS4Item} item The item for which to get effects
* @returns The array of effects that are candidates to be applied to the item * @returns {import("../active-effect").DS4ActiveEffect[]} The array of effects that are candidates to be applied to the item
*/ */
itemEffects(item) { itemEffects(item) {
return this.effects.filter((effect) => { return this.effects.filter((effect) => {
const { applyToItems, itemName, condition } = effect.data.flags.ds4?.itemEffectConfig ?? {}; const { applyToItems, itemName, condition } = effect.flags.ds4?.itemEffectConfig ?? {};
if (!applyToItems || (itemName !== undefined && itemName !== "" && itemName !== item.name)) { if (!applyToItems || (itemName !== undefined && itemName !== "" && itemName !== item.name)) {
return false; return false;
@ -82,9 +79,9 @@ export class DS4Actor extends Actor {
if (condition !== undefined && condition !== "") { if (condition !== undefined && condition !== "") {
try { try {
const replacedCondition = DS4Actor.replaceFormulaData(condition, { const replacedCondition = DS4Actor.replaceFormulaData(condition, {
item: item.data, item,
actor: this.data, actor: this,
effect: effect.data, effect,
}); });
return replacedCondition !== undefined ? Boolean(mathEvaluator.evaluate(replacedCondition)) : false; return replacedCondition !== undefined ? Boolean(mathEvaluator.evaluate(replacedCondition)) : false;
} catch (error) { } catch (error) {
@ -189,7 +186,7 @@ export class DS4Actor extends Actor {
* @override * @override
*/ */
prepareDerivedData() { prepareDerivedData() {
this.data.data.armorValueSpellMalus = Math.max(this.data.data.armorValueSpellMalus, 0); this.system.armorValueSpellMalus = Math.max(this.system.armorValueSpellMalus, 0);
this.prepareCombatValues(); this.prepareCombatValues();
this.prepareChecks(); this.prepareChecks();
} }
@ -200,11 +197,11 @@ export class DS4Actor extends Actor {
*/ */
get derivedDataProperties() { get derivedDataProperties() {
const combatValueProperties = Object.keys(DS4.i18n.combatValues).map( const combatValueProperties = Object.keys(DS4.i18n.combatValues).map(
(combatValue) => `data.combatValues.${combatValue}.total`, (combatValue) => `system.combatValues.${combatValue}.total`,
); );
const checkProperties = Object.keys(DS4.i18n.checks) const checkProperties = Object.keys(DS4.i18n.checks)
.filter((check) => check !== "defend") .filter((check) => check !== "defend")
.map((check) => `data.checks.${check}`); .map((check) => `system.checks.${check}`);
return combatValueProperties.concat(checkProperties); return combatValueProperties.concat(checkProperties);
} }
@ -212,18 +209,17 @@ export class DS4Actor extends Actor {
* Apply final transformations to the Actor data after all effects have been applied. * Apply final transformations to the Actor data after all effects have been applied.
*/ */
prepareFinalDerivedData() { prepareFinalDerivedData() {
Object.values(this.data.data.attributes).forEach((attribute) => (attribute.total = Math.ceil(attribute.total))); Object.values(this.system.attributes).forEach((attribute) => (attribute.total = Math.ceil(attribute.total)));
Object.values(this.data.data.traits).forEach((trait) => (trait.total = Math.ceil(trait.total))); Object.values(this.system.traits).forEach((trait) => (trait.total = Math.ceil(trait.total)));
Object.entries(this.data.data.combatValues) Object.entries(this.system.combatValues)
.filter(([key]) => key !== "movement") .filter(([key]) => key !== "movement")
.map(([, value]) => value) .forEach(([, combatValue]) => (combatValue.total = Math.ceil(combatValue.total)));
.forEach((combatValue) => (combatValue.total = Math.ceil(combatValue.total))); Object.keys(this.system.checks).forEach((key) => {
Object.keys(this.data.data.checks).forEach((key) => { this.system.checks[key] = Math.ceil(this.system.checks[key]);
this.data.data.checks[key] = Math.ceil(this.data.data.checks[key]);
}); });
this.data.data.combatValues.hitPoints.max = this.data.data.combatValues.hitPoints.total; this.system.combatValues.hitPoints.max = this.system.combatValues.hitPoints.total;
this.data.data.checks.defend = this.data.data.combatValues.defense.total; this.system.checks.defend = this.system.combatValues.defense.total;
} }
/** /**
@ -232,7 +228,7 @@ export class DS4Actor extends Actor {
* @type {string[]} * @type {string[]}
*/ */
get finalDerivedDataProperties() { get finalDerivedDataProperties() {
return ["data.combatValues.hitPoints.max", "data.checks.defend"]; return ["system.combatValues.hitPoints.max", "system.checks.defend"];
} }
/** /**
@ -257,21 +253,21 @@ export class DS4Actor extends Actor {
* @protected * @protected
*/ */
prepareCombatValues() { prepareCombatValues() {
const data = this.data.data; const system = this.system;
data.combatValues.hitPoints.base = data.attributes.body.total + data.traits.constitution.total + 10; system.combatValues.hitPoints.base = system.attributes.body.total + system.traits.constitution.total + 10;
data.combatValues.defense.base = system.combatValues.defense.base =
data.attributes.body.total + data.traits.constitution.total + this.armorValueOfEquippedItems; system.attributes.body.total + system.traits.constitution.total + this.armorValueOfEquippedItems;
data.combatValues.initiative.base = data.attributes.mobility.total + data.traits.agility.total; system.combatValues.initiative.base = system.attributes.mobility.total + system.traits.agility.total;
data.combatValues.movement.base = data.attributes.mobility.total / 2 + 1; system.combatValues.movement.base = system.attributes.mobility.total / 2 + 1;
data.combatValues.meleeAttack.base = data.attributes.body.total + data.traits.strength.total; system.combatValues.meleeAttack.base = system.attributes.body.total + system.traits.strength.total;
data.combatValues.rangedAttack.base = data.attributes.mobility.total + data.traits.dexterity.total; system.combatValues.rangedAttack.base = system.attributes.mobility.total + system.traits.dexterity.total;
data.combatValues.spellcasting.base = system.combatValues.spellcasting.base =
data.attributes.mind.total + data.traits.aura.total - data.armorValueSpellMalus; system.attributes.mind.total + system.traits.aura.total - system.armorValueSpellMalus;
data.combatValues.targetedSpellcasting.base = system.combatValues.targetedSpellcasting.base =
data.attributes.mind.total + data.traits.dexterity.total - data.armorValueSpellMalus; system.attributes.mind.total + system.traits.dexterity.total - system.armorValueSpellMalus;
Object.values(data.combatValues).forEach( Object.values(system.combatValues).forEach(
(combatValue) => (combatValue.total = combatValue.base + combatValue.mod), (combatValue) => (combatValue.total = combatValue.base + combatValue.mod),
); );
} }
@ -282,7 +278,7 @@ export class DS4Actor extends Actor {
* @protected * @protected
*/ */
get armorValueOfEquippedItems() { get armorValueOfEquippedItems() {
return this.equippedItemsWithArmor.map((item) => item.data.data.armorValue).reduce((a, b) => a + b, 0); return this.equippedItemsWithArmor.map((item) => item.system.armorValue).reduce((a, b) => a + b, 0);
} }
/** /**
@ -292,12 +288,8 @@ export class DS4Actor extends Actor {
*/ */
get armorValueSpellMalusOfEquippedItems() { get armorValueSpellMalusOfEquippedItems() {
return this.equippedItemsWithArmor return this.equippedItemsWithArmor
.filter( .filter((item) => !(item.type === "armor" && ["cloth", "natural"].includes(item.system.armorMaterialType)))
(item) => .reduce((sum, item) => sum + item.system.armorValue, 0);
!(item.data.type === "armor" && ["cloth", "natural"].includes(item.data.data.armorMaterialType)),
)
.map((item) => item.data.data.armorValue)
.reduce((a, b) => a + b, 0);
} }
/** /**
@ -306,9 +298,7 @@ export class DS4Actor extends Actor {
* @protected * @protected
*/ */
get equippedItemsWithArmor() { get equippedItemsWithArmor() {
return this.items return this.items.filter((item) => (item.type === "armor" || item.type === "shield") && item.system.equipped);
.filter((item) => item.data.type === "armor" || item.data.type === "shield")
.filter((item) => item.data.data.equipped);
} }
/** /**
@ -316,57 +306,63 @@ export class DS4Actor extends Actor {
* @protected * @protected
*/ */
prepareChecks() { prepareChecks() {
const data = this.data.data; const system = this.system;
data.checks = { system.checks = {
appraise: data.attributes.mind.total + data.traits.intellect.total, appraise: system.attributes.mind.total + system.traits.intellect.total,
changeSpell: data.attributes.mind.total + data.traits.intellect.total, changeSpell: system.attributes.mind.total + system.traits.intellect.total,
climb: data.attributes.mobility.total + data.traits.strength.total, climb: system.attributes.mobility.total + system.traits.strength.total,
communicate: data.attributes.mind.total + data.traits.dexterity.total + this.itemTypes.language.length, communicate: system.attributes.mind.total + system.traits.dexterity.total + this.itemTypes.language.length,
decipherScript: data.attributes.mind.total + data.traits.intellect.total, decipherScript: system.attributes.mind.total + system.traits.intellect.total,
defend: 0, // assigned in prepareFinalDerivedData as it must always match data.combatValues.defense.total and is not changeable by effects defend: 0, // assigned in prepareFinalDerivedData as it must always match data.combatValues.defense.total and is not changeable by effects
defyPoison: data.attributes.body.total + data.traits.constitution.total, defyPoison: system.attributes.body.total + system.traits.constitution.total,
disableTraps: data.attributes.mind.total + data.traits.dexterity.total, disableTraps: system.attributes.mind.total + system.traits.dexterity.total,
featOfStrength: data.attributes.body.total + data.traits.strength.total, featOfStrength: system.attributes.body.total + system.traits.strength.total,
flirt: data.attributes.mind.total + data.traits.aura.total, flirt: system.attributes.mind.total + system.traits.aura.total,
haggle: data.attributes.mind.total + Math.max(data.traits.intellect.total, data.traits.intellect.total), haggle:
hide: data.attributes.mobility.total + data.traits.agility.total, system.attributes.mind.total + Math.max(system.traits.intellect.total, system.traits.intellect.total),
identifyMagic: data.attributes.mind.total + data.traits.intellect.total, hide: system.attributes.mobility.total + system.traits.agility.total,
jump: data.attributes.mobility.total + data.traits.agility.total, identifyMagic: system.attributes.mind.total + system.traits.intellect.total,
knowledge: data.attributes.mind.total + data.traits.intellect.total, jump: system.attributes.mobility.total + system.traits.agility.total,
openLock: data.attributes.mind.total + data.traits.dexterity.total, knowledge: system.attributes.mind.total + system.traits.intellect.total,
perception: Math.max(data.attributes.mind.total + data.traits.intellect.total, 8), openLock: system.attributes.mind.total + system.traits.dexterity.total,
pickPocket: data.attributes.mobility.total + data.traits.dexterity.total, perception: Math.max(system.attributes.mind.total + system.traits.intellect.total, 8),
readTracks: data.attributes.mind.total + data.traits.intellect.total, pickPocket: system.attributes.mobility.total + system.traits.dexterity.total,
resistDisease: data.attributes.body.total + data.traits.constitution.total, readTracks: system.attributes.mind.total + system.traits.intellect.total,
ride: data.attributes.mobility.total + Math.max(data.traits.agility.total, data.traits.aura.total), resistDisease: system.attributes.body.total + system.traits.constitution.total,
search: Math.max(data.attributes.mind.total + data.traits.intellect.total, 8), ride: system.attributes.mobility.total + Math.max(system.traits.agility.total, system.traits.aura.total),
senseMagic: data.attributes.mind.total + data.traits.aura.total, search: Math.max(system.attributes.mind.total + system.traits.intellect.total, 8),
sneak: data.attributes.mobility.total + data.traits.agility.total, senseMagic: system.attributes.mind.total + system.traits.aura.total,
startFire: data.attributes.mind.total + data.traits.dexterity.total, sneak: system.attributes.mobility.total + system.traits.agility.total,
swim: data.attributes.mobility.total + data.traits.strength.total, startFire: system.attributes.mind.total + system.traits.dexterity.total,
wakeUp: data.attributes.mind.total + data.traits.intellect.total, swim: system.attributes.mobility.total + system.traits.strength.total,
wakeUp: system.attributes.mind.total + system.traits.intellect.total,
workMechanism: workMechanism:
data.attributes.mind.total + Math.max(data.traits.dexterity.total, data.traits.intellect.total), system.attributes.mind.total + Math.max(system.traits.dexterity.total, system.traits.intellect.total),
}; };
} }
/** /**
* Handle how changes to a Token attribute bar are applied to the Actor. * Handle how changes to a Token attribute bar are applied to the Actor.
* This only differs from the base implementation by also allowing negative values. * This only differs from the base implementation by also allowing negative values.
* @param {string} attribute The attribute path
* @param {number} value The target attribute value
* @param {boolean} [isDelta=false] Whether the number represents a relative change (true) or an absolute change (false)
* @param {boolean} [isBar=true] Whether the new value is part of an attribute bar, or just a direct value
* @returns {Promise<DS4Actor>} The updated Actor document
* @override * @override
*/ */
async modifyTokenAttribute(attribute, value, isDelta = false, isBar = true) { async modifyTokenAttribute(attribute, value, isDelta = false, isBar = true) {
const current = foundry.utils.getProperty(this.data.data, attribute); const current = foundry.utils.getProperty(this.system, attribute);
// Determine the updates to make to the actor data // Determine the updates to make to the actor data
/** @type {Record<string, number>} */ /** @type {Record<string, number>} */
let updates; let updates;
if (isBar) { if (isBar) {
if (isDelta) value = Math.min(Number(current.value) + value, current.max); if (isDelta) value = Math.min(Number(current.value) + value, current.max);
updates = { [`data.${attribute}.value`]: value }; updates = { [`system.${attribute}.value`]: value };
} else { } else {
if (isDelta) value = Number(current) + value; if (isDelta) value = Number(current) + value;
updates = { [`data.${attribute}`]: value }; updates = { [`system.${attribute}`]: value };
} }
// Call a hook to handle token resource bar updates // Call a hook to handle token resource bar updates
@ -382,10 +378,10 @@ export class DS4Actor extends Actor {
*/ */
async rollCheck(check, options = {}) { async rollCheck(check, options = {}) {
const speaker = ChatMessage.getSpeaker({ actor: this, ...options.speaker }); const speaker = ChatMessage.getSpeaker({ actor: this, ...options.speaker });
await createCheckRoll(this.data.data.checks[check], { await createCheckRoll(this.system.checks[check], {
rollMode: getGame().settings.get("core", "rollMode"), rollMode: getGame().settings.get("core", "rollMode"),
maximumCoupResult: this.data.data.rolling.maximumCoupResult, maximumCoupResult: this.system.rolling.maximumCoupResult,
minimumFumbleResult: this.data.data.rolling.minimumFumbleResult, minimumFumbleResult: this.system.rolling.minimumFumbleResult,
flavor: "DS4.ActorCheckFlavor", flavor: "DS4.ActorCheckFlavor",
flavorData: { actor: speaker.alias ?? this.name, check: DS4.i18nKeys.checks[check] }, flavorData: { actor: speaker.alias ?? this.name, check: DS4.i18nKeys.checks[check] },
speaker, speaker,
@ -404,12 +400,12 @@ export class DS4Actor extends Actor {
return; return;
} }
const { attribute, trait } = attributeAndTrait; const { attribute, trait } = attributeAndTrait;
const checkTargetNumber = this.data.data.attributes[attribute].total + this.data.data.traits[trait].total; const checkTargetNumber = this.system.attributes[attribute].total + this.system.traits[trait].total;
const speaker = ChatMessage.getSpeaker({ actor: this, ...options.speaker }); const speaker = ChatMessage.getSpeaker({ actor: this, ...options.speaker });
await createCheckRoll(checkTargetNumber, { await createCheckRoll(checkTargetNumber, {
rollMode: getGame().settings.get("core", "rollMode"), rollMode: getGame().settings.get("core", "rollMode"),
maximumCoupResult: this.data.data.rolling.maximumCoupResult, maximumCoupResult: this.system.rolling.maximumCoupResult,
minimumFumbleResult: this.data.data.rolling.minimumFumbleResult, minimumFumbleResult: this.system.rolling.minimumFumbleResult,
flavor: "DS4.ActorGenericCheckFlavor", flavor: "DS4.ActorGenericCheckFlavor",
flavorData: { flavorData: {
actor: speaker.alias ?? this.name, actor: speaker.alias ?? this.name,
@ -438,7 +434,7 @@ export class DS4Actor extends Actor {
options: Object.fromEntries( options: Object.fromEntries(
Object.entries(DS4.i18n.attributes).map(([attribute, translation]) => [ Object.entries(DS4.i18n.attributes).map(([attribute, translation]) => [
attribute, attribute,
`${translation} (${this.data.data.attributes[attribute].total})`, `${translation} (${this.system.attributes[attribute].total})`,
]), ]),
), ),
}, },
@ -448,7 +444,7 @@ export class DS4Actor extends Actor {
options: Object.fromEntries( options: Object.fromEntries(
Object.entries(DS4.i18n.traits).map(([trait, translation]) => [ Object.entries(DS4.i18n.traits).map(([trait, translation]) => [
trait, trait,
`${translation} (${this.data.data.traits[trait].total})`, `${translation} (${this.system.traits[trait].total})`,
]), ]),
), ),
}, },

View file

@ -8,12 +8,12 @@ export class DS4Character extends DS4Actor {
/** @override */ /** @override */
prepareFinalDerivedData() { prepareFinalDerivedData() {
super.prepareFinalDerivedData(); super.prepareFinalDerivedData();
this.data.data.slayerPoints.max = 3; this.system.slayerPoints.max = 3;
} }
/** @override */ /** @override */
get finalDerivedDataProperties() { get finalDerivedDataProperties() {
return [...super.finalDerivedDataProperties, "data.slayerPoints.max"]; return [...super.finalDerivedDataProperties, "system.slayerPoints.max"];
} }
/** @override */ /** @override */

View file

@ -17,15 +17,15 @@ import { getGame } from "../utils/utils";
export class DS4ChatMessage extends ChatMessage { export class DS4ChatMessage extends ChatMessage {
prepareData() { prepareData() {
super.prepareData(); super.prepareData();
if (this.data.flavor) { if (this.flavor) {
const game = getGame(); const game = getGame();
const flavorData = Object.fromEntries( const flavorData = Object.fromEntries(
Object.entries(this.data.flags.ds4?.flavorData ?? {}).map(([key, value]) => [ Object.entries(this.flags.ds4?.flavorData ?? {}).map(([key, value]) => [
key, key,
typeof value === "string" ? game.i18n.localize(value) : value, typeof value === "string" ? game.i18n.localize(value) : value,
]), ]),
); );
this.data.flavor = game.i18n.format(this.data.flavor, flavorData); this.flavor = game.i18n.format(this.flavor, flavorData);
} }
} }
} }

View file

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT
/**
* @typedef {object} RollOptions
* @property {Speaker} speaker
*/
/**
* @typedef {object} Speaker
* @property {TokenDocument} [token]
* @property {string} [alias]
*/
export {}

View file

@ -17,10 +17,6 @@ export interface DS4ItemDataSourceDataPhysical {
storageLocation: string; storageLocation: string;
} }
export function isDS4ItemDataTypePhysical(input: object): boolean {
return "quantity" in input && "price" in input && "availability" in input && "storageLocation" in input;
}
export interface DS4ItemDataSourceDataEquipable { export interface DS4ItemDataSourceDataEquipable {
equipped: boolean; equipped: boolean;
} }

View file

@ -17,7 +17,7 @@ export class DS4Item extends Item {
/** @override */ /** @override */
prepareDerivedData() { prepareDerivedData() {
this.data.data.rollable = false; this.system.rollable = false;
} }
/** /**
@ -25,7 +25,7 @@ export class DS4Item extends Item {
* @returns {boolean} Whether the item is a non-equpped equibale or not * @returns {boolean} Whether the item is a non-equpped equibale or not
*/ */
isNonEquippedEuipable() { isNonEquippedEuipable() {
return "equipped" in this.data.data && !this.data.data.equipped; return "equipped" in this.system && !this.system.equipped;
} }
/** /**
@ -52,6 +52,6 @@ export class DS4Item extends Item {
*/ */
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
async roll(options = {}) { async roll(options = {}) {
throw new Error(getGame().i18n.format("DS4.ErrorRollingForItemTypeNotPossible", { type: this.data.type })); throw new Error(getGame().i18n.format("DS4.ErrorRollingForItemTypeNotPossible", { type: this.type }));
} }
} }

View file

@ -11,10 +11,10 @@ import { calculateSpellPrice } from "./calculate-spell-price";
export class DS4Spell extends DS4Item { export class DS4Spell extends DS4Item {
/** @override */ /** @override */
prepareDerivedData() { prepareDerivedData() {
this.data.data.rollable = this.data.data.equipped; this.system.rollable = this.system.equipped;
this.data.data.price = calculateSpellPrice(this.data.data); this.system.price = calculateSpellPrice(this.system);
if (this.data.data.allowsDefense) { if (this.system.allowsDefense) {
this.data.data.opponentDefense = 0; this.system.opponentDefense = 0;
} }
} }
@ -22,12 +22,12 @@ export class DS4Spell extends DS4Item {
async roll(options = {}) { async roll(options = {}) {
const game = getGame(); const game = getGame();
if (!this.data.data.equipped) { if (!this.system.equipped) {
return notifications.warn( return notifications.warn(
game.i18n.format("DS4.WarningItemMustBeEquippedToBeRolled", { game.i18n.format("DS4.WarningItemMustBeEquippedToBeRolled", {
name: this.name, name: this.name,
id: this.id, id: this.id,
type: this.data.type, type: this.type,
}), }),
); );
} }
@ -36,21 +36,21 @@ export class DS4Spell extends DS4Item {
throw new Error(game.i18n.format("DS4.ErrorCannotRollUnownedItem", { name: this.name, id: this.id })); throw new Error(game.i18n.format("DS4.ErrorCannotRollUnownedItem", { name: this.name, id: this.id }));
} }
const ownerDataData = this.actor.data.data; const ownerSystemData = this.actor.system;
const hasComplexModifier = this.data.data.spellModifier.complex !== ""; const hasComplexModifier = this.system.spellModifier.complex !== "";
if (hasComplexModifier === undefined) { if (hasComplexModifier === undefined) {
notifications.info( notifications.info(
game.i18n.format("DS4.InfoManuallyEnterSpellModifier", { game.i18n.format("DS4.InfoManuallyEnterSpellModifier", {
name: this.name, name: this.name,
spellModifier: this.data.data.spellModifier.complex, spellModifier: this.system.spellModifier.complex,
}), }),
); );
} }
const spellType = this.data.data.spellType; const spellType = this.system.spellType;
const opponentDefense = this.data.data.opponentDefense; const opponentDefense = this.system.opponentDefense;
const checkTargetNumber = const checkTargetNumber =
ownerDataData.combatValues[spellType].total + ownerSystemData.combatValues[spellType].total +
(hasComplexModifier ? 0 : this.data.data.spellModifier.numerical); (hasComplexModifier ? 0 : this.system.spellModifier.numerical);
const speaker = ChatMessage.getSpeaker({ actor: this.actor, ...options.speaker }); const speaker = ChatMessage.getSpeaker({ actor: this.actor, ...options.speaker });
const flavor = const flavor =
opponentDefense !== undefined && opponentDefense !== 0 opponentDefense !== undefined && opponentDefense !== 0
@ -67,8 +67,8 @@ export class DS4Spell extends DS4Item {
await createCheckRoll(checkTargetNumber, { await createCheckRoll(checkTargetNumber, {
rollMode: game.settings.get("core", "rollMode"), rollMode: game.settings.get("core", "rollMode"),
maximumCoupResult: ownerDataData.rolling.maximumCoupResult, maximumCoupResult: ownerSystemData.rolling.maximumCoupResult,
minimumFumbleResult: ownerDataData.rolling.minimumFumbleResult, minimumFumbleResult: ownerSystemData.rolling.minimumFumbleResult,
flavor: flavor, flavor: flavor,
flavorData: flavorData, flavorData: flavorData,
speaker, speaker,

View file

@ -8,12 +8,11 @@ export class DS4Talent extends DS4Item {
/** @override */ /** @override */
prepareDerivedData() { prepareDerivedData() {
super.prepareDerivedData(); super.prepareDerivedData();
const data = this.data.data; this.system.rank.total = this.system.rank.base + this.system.rank.mod;
data.rank.total = data.rank.base + data.rank.mod;
} }
/** @override */ /** @override */
get activeEffectFactor() { get activeEffectFactor() {
return this.data.data.rank.total; return this.system.rank.total;
} }
} }

View file

@ -11,26 +11,26 @@ import { DS4Item } from "../item";
export class DS4Weapon extends DS4Item { export class DS4Weapon extends DS4Item {
/** @override */ /** @override */
prepareDerivedData() { prepareDerivedData() {
const data = this.data.data; const system = this.system;
data.rollable = data.equipped; system.rollable = system.equipped;
data.opponentDefenseForAttackType = {}; system.opponentDefenseForAttackType = {};
if (data.attackType === "melee" || data.attackType === "meleeRanged") { if (system.attackType === "melee" || system.attackType === "meleeRanged") {
data.opponentDefenseForAttackType.melee = data.opponentDefense; system.opponentDefenseForAttackType.melee = system.opponentDefense;
} }
if (data.attackType === "ranged" || data.attackType === "meleeRanged") { if (system.attackType === "ranged" || system.attackType === "meleeRanged") {
data.opponentDefenseForAttackType.ranged = data.opponentDefense; system.opponentDefenseForAttackType.ranged = system.opponentDefense;
} }
} }
/** @override */ /** @override */
async roll(options = {}) { async roll(options = {}) {
const game = getGame(); const game = getGame();
if (!this.data.data.equipped) { if (!this.system.equipped) {
return notifications.warn( return notifications.warn(
game.i18n.format("DS4.WarningItemMustBeEquippedToBeRolled", { game.i18n.format("DS4.WarningItemMustBeEquippedToBeRolled", {
name: this.name, name: this.name,
id: this.id, id: this.id,
type: this.data.type, type: this.type,
}), }),
); );
} }
@ -39,12 +39,12 @@ export class DS4Weapon extends DS4Item {
throw new Error(game.i18n.format("DS4.ErrorCannotRollUnownedItem", { name: this.name, id: this.id })); throw new Error(game.i18n.format("DS4.ErrorCannotRollUnownedItem", { name: this.name, id: this.id }));
} }
const ownerDataData = this.actor.data.data; const ownerSystemData = this.actor.system;
const weaponBonus = this.data.data.weaponBonus; const weaponBonus = this.system.weaponBonus;
const attackType = await this.getPerformedAttackType(); const attackType = await this.getPerformedAttackType();
const opponentDefense = this.data.data.opponentDefenseForAttackType[attackType]; const opponentDefense = this.system.opponentDefenseForAttackType[attackType];
const combatValue = `${attackType}Attack`; const combatValue = `${attackType}Attack`;
const checkTargetNumber = ownerDataData.combatValues[combatValue].total + weaponBonus; const checkTargetNumber = ownerSystemData.combatValues[combatValue].total + weaponBonus;
const speaker = ChatMessage.getSpeaker({ actor: this.actor, ...options.speaker }); const speaker = ChatMessage.getSpeaker({ actor: this.actor, ...options.speaker });
const flavor = const flavor =
opponentDefense !== undefined && opponentDefense !== 0 opponentDefense !== undefined && opponentDefense !== 0
@ -61,8 +61,8 @@ export class DS4Weapon extends DS4Item {
await createCheckRoll(checkTargetNumber, { await createCheckRoll(checkTargetNumber, {
rollMode: getGame().settings.get("core", "rollMode"), rollMode: getGame().settings.get("core", "rollMode"),
maximumCoupResult: ownerDataData.rolling.maximumCoupResult, maximumCoupResult: ownerSystemData.rolling.maximumCoupResult,
minimumFumbleResult: ownerDataData.rolling.minimumFumbleResult, minimumFumbleResult: ownerSystemData.rolling.minimumFumbleResult,
speaker, speaker,
flavor, flavor,
flavorData, flavorData,
@ -77,8 +77,8 @@ export class DS4Weapon extends DS4Item {
* @protected * @protected
*/ */
async getPerformedAttackType() { async getPerformedAttackType() {
if (this.data.data.attackType !== "meleeRanged") { if (this.system.attackType !== "meleeRanged") {
return this.data.data.attackType; return this.system.attackType;
} }
const { melee, ranged } = { ...DS4.i18n.attackTypes }; const { melee, ranged } = { ...DS4.i18n.attackTypes };

View file

@ -12,7 +12,7 @@ function getFallbackData() {
if (!fallbackData) { if (!fallbackData) {
fallbackData = {}; fallbackData = {};
for (const type of getGame().system.template.Actor?.types ?? []) { for (const type of getGame().system.template.Actor?.types ?? []) {
foundry.utils.mergeObject(fallbackData, new DS4ActorProxy({ type, name: "temporary" }).data.data); foundry.utils.mergeObject(fallbackData, new DS4ActorProxy({ type, name: "temporary" }).system);
} }
} }
return fallbackData; return fallbackData;

View file

@ -2,12 +2,8 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import { isCheck } from "../documents/actor/actor-data-properties-base";
import { DS4Item } from "../documents/item/item";
import { createRollCheckMacro } from "../macros/roll-check"; import { createRollCheckMacro } from "../macros/roll-check";
import { createRollItemMacro } from "../macros/roll-item"; import { createRollItemMacro } from "../macros/roll-item";
import { notifications } from "../ui/notifications";
import { getGame } from "../utils/utils";
export function registerForHotbarDropHook() { export function registerForHotbarDropHook() {
Hooks.on("hotbarDrop", onHotbarDrop); Hooks.on("hotbarDrop", onHotbarDrop);
@ -23,32 +19,17 @@ export function registerForHotbarDropHook() {
* @param {Hotbar} hotbar The hotbar on which something wqas * @param {Hotbar} hotbar The hotbar on which something wqas
* @param {DropData} data The drop data associated to the drop event * @param {DropData} data The drop data associated to the drop event
* @param {string} slot The slot on the hotbar that somethingwas dropped on * @param {string} slot The slot on the hotbar that somethingwas dropped on
* @returns {Promise<void>} * @returns {void | false}
*/ */
async function onHotbarDrop(hotbar, data, slot) { function onHotbarDrop(hotbar, data, slot) {
switch (data.type) { switch (data.type) {
case "Item": { case "Item": {
if (!("data" in data)) { createRollItemMacro(data, slot);
return notifications.warn(getGame().i18n.localize("DS4.WarningMacrosCanOnlyBeCreatedForOwnedItems")); return false;
}
const itemData = data.data;
if (!DS4Item.rollableItemTypes.includes(itemData.type)) {
return notifications.warn(
getGame().i18n.format("DS4.WarningItemIsNotRollable", {
name: itemData.name,
id: itemData._id,
type: itemData.type,
}),
);
}
return createRollItemMacro(itemData, slot);
} }
case "Check": { case "Check": {
if (!("data" in data) || typeof data.data !== "string" || !isCheck(data.data)) { createRollCheckMacro(data, slot);
return notifications.warn(getGame().i18n.localize("DS4.WarningInvalidCheckDropped")); return false;
}
return createRollCheckMacro(data.data, slot);
} }
} }
} }

View file

@ -3,6 +3,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import { DS4 } from "../config"; import { DS4 } from "../config";
import { isCheck } from "../documents/actor/actor-data-properties-base";
import { notifications } from "../ui/notifications"; import { notifications } from "../ui/notifications";
import { getGame } from "../utils/utils"; import { getGame } from "../utils/utils";
import { getActiveActorAndToken } from "./helpers"; import { getActiveActorAndToken } from "./helpers";
@ -10,12 +11,15 @@ import { getActiveActorAndToken } from "./helpers";
/** /**
* Creates a macro from a check drop. * Creates a macro from a check drop.
* Get an existing roll check macro if one exists, otherwise create a new one. * Get an existing roll check macro if one exists, otherwise create a new one.
* @param {import("../documents/actor/actor-data-properties-base").Check} check The name of the check to perform * @param {object} data The check drop data
* @param {string} slot The hotbar slot to use * @param {string} slot The hotbar slot to use
* @returns {Promise<void>} A promise that resoolves when the macro has been created. * @returns {Promise<void>} A promise that resolves when the macro has been created.
*/ */
export async function createRollCheckMacro(check, slot) { export async function createRollCheckMacro(data, slot) {
const macro = await getOrCreateRollCheckMacro(check); if (!("data" in data) || typeof data.data !== "string" || !isCheck(data.data)) {
return notifications.warn(getGame().i18n.localize("DS4.WarningInvalidCheckDropped"));
}
const macro = await getOrCreateRollCheckMacro(data.data);
await getGame().user?.assignHotbarMacro(macro ?? null, slot); await getGame().user?.assignHotbarMacro(macro ?? null, slot);
} }
@ -26,9 +30,7 @@ export async function createRollCheckMacro(check, slot) {
async function getOrCreateRollCheckMacro(check) { async function getOrCreateRollCheckMacro(check) {
const command = `game.ds4.macros.rollCheck("${check}");`; const command = `game.ds4.macros.rollCheck("${check}");`;
const existingMacro = getGame().macros?.find( const existingMacro = getGame().macros?.find((m) => m.name === DS4.i18n.checks[check] && m.command === command);
(m) => m.name === DS4.i18n.checks[check] && m.data.command === command,
);
if (existingMacro) { if (existingMacro) {
return existingMacro; return existingMacro;
} }

View file

@ -2,18 +2,33 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import { DS4Item } from "../documents/item/item";
import { notifications } from "../ui/notifications"; import { notifications } from "../ui/notifications";
import { getGame } from "../utils/utils"; import { getGame } from "../utils/utils";
import { getActiveActorAndToken } from "./helpers"; import { getActiveActorAndToken } from "./helpers";
/** /**
* Creates a macro from an item drop. * Create a macro from an item drop.
* Get an existing roll item macro if one exists, otherwise create a new one. * Get an existing roll item macro if one exists, otherwise create a new one.
* @param {object} itemData The item data * @param {object} data The item drop data
* @param {string} slot The hotbar slot to use * @param {string} slot The hotbar slot to use
* @returns {Promise<void>} A promise that resolves once the macro has been created. * @returns {Promise<void>} A promise that resolves once the macro has been created.
*/ */
export async function createRollItemMacro(itemData, slot) { export async function createRollItemMacro(data, slot) {
const item = await Item.implementation.fromDropData(data);
if (!item.parent) {
return notifications.warn(getGame().i18n.localize("DS4.WarningMacrosCanOnlyBeCreatedForOwnedItems"));
}
if (!DS4Item.rollableItemTypes.includes(item.type)) {
return notifications.warn(
getGame().i18n.format("DS4.WarningItemIsNotRollable", {
name: item.name,
id: item.id,
type: item.type,
}),
);
}
const macro = await getOrCreateRollItemMacro(itemData); const macro = await getOrCreateRollItemMacro(itemData);
await getGame().user?.assignHotbarMacro(macro ?? null, slot); await getGame().user?.assignHotbarMacro(macro ?? null, slot);
} }

View file

@ -20,7 +20,7 @@ async function migrate() {
/** @type {import("./migrationHelpers").ActorUpdateDataGetter} */ /** @type {import("./migrationHelpers").ActorUpdateDataGetter} */
function getActorUpdateData() { function getActorUpdateData() {
const updateData = { const updateData = {
data: { system: {
combatValues: [ combatValues: [
"hitPoints", "hitPoints",
"defense", "defense",

View file

@ -24,7 +24,7 @@ async function migrate() {
function getItemUpdateData(itemData) { function getItemUpdateData(itemData) {
if (!["loot"].includes(itemData.type ?? "")) return undefined; if (!["loot"].includes(itemData.type ?? "")) return undefined;
return { return {
data: { system: {
"-=equipped": null, "-=equipped": null,
}, },
}; };

View file

@ -23,10 +23,10 @@ async function migrate() {
/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */ /** @type {import("./migrationHelpers").ItemUpdateDataGetter} */
function getItemUpdateData(itemData) { function getItemUpdateData(itemData) {
if (itemData.type !== "spell") return; if (itemData.type !== "spell") return;
const cooldownDurationUnit = itemData.data?.cooldownDuration.unit; const cooldownDurationUnit = itemData.system?.cooldownDuration.unit;
const updateData = { const updateData = {
data: { system: {
"-=scrollPrice": null, "-=scrollPrice": null,
minimumLevels: { healer: null, wizard: null, sorcerer: null }, minimumLevels: { healer: null, wizard: null, sorcerer: null },
cooldownDuration: { cooldownDuration: {

View file

@ -32,12 +32,12 @@ async function migrate() {
/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */ /** @type {import("./migrationHelpers").ItemUpdateDataGetter} */
function getItemUpdateData(itemData) { function getItemUpdateData(itemData) {
if (itemData.type !== "spell") return; if (itemData.type !== "spell") return;
const cooldownDurationUnit = itemData.data?.cooldownDuration.unit; const cooldownDurationUnit = itemData.system?.cooldownDuration.unit;
const cooldownDurationValue = itemData.data?.cooldownDuration.value; const cooldownDurationValue = itemData.system?.cooldownDuration.value;
const cooldownDuration = migrateCooldownDuration(cooldownDurationValue, cooldownDurationUnit); const cooldownDuration = migrateCooldownDuration(cooldownDurationValue, cooldownDurationUnit);
const updateData = { const updateData = {
data: { system: {
cooldownDuration, cooldownDuration,
}, },
}; };

View file

@ -23,15 +23,15 @@ async function migrate() {
/** @type {import("./migrationHelpers").ItemUpdateDataGetter} */ /** @type {import("./migrationHelpers").ItemUpdateDataGetter} */
function getItemUpdateData(itemData) { function getItemUpdateData(itemData) {
if (itemData.type !== "spell") return; if (itemData.type !== "spell") return;
const spellCategory = itemData.data?.spellCategory; const spellCategory = itemData.system?.spellCategory;
const spellGroups = migrateSpellCategory(spellCategory); const spellGroups = migrateSpellCategory(spellCategory);
// @ts-expect-error bonus is removed with this migration // @ts-expect-error bonus is removed with this migration
const bonus = itemData.data?.bonus; const bonus = itemData.system?.bonus;
const spellModifier = migrateBonus(bonus); const spellModifier = migrateBonus(bonus);
const updateData = { const updateData = {
data: { system: {
spellGroups, spellGroups,
"-=spellCategory": null, "-=spellCategory": null,
spellModifier, spellModifier,

View file

@ -25,7 +25,7 @@ function getItemUpdateData(itemData) {
if (itemData.type !== "spell") return; if (itemData.type !== "spell") return;
return { return {
data: { system: {
allowsDefense: false, allowsDefense: false,
}, },
}; };

61
src/migration/008.js Normal file
View file

@ -0,0 +1,61 @@
// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT
import {
getActorUpdateDataGetter,
getCompendiumMigrator,
getItemUpdateDataGetter,
getSceneUpdateDataGetter,
migrateActors,
migrateCompendiums,
migrateItems,
migrateScenes,
} from "./migrationHelpers";
/** @type {import("./migration").Migration["migrate"]} */
async function migrate() {
await migrateItems(getItemUpdateData);
await migrateActors(getActorUpdateData);
await migrateScenes(getSceneUpdateData);
await migrateCompendiums(migrateCompendium);
}
/** @type {import("./migrationHelpers").EffectUpdateDataGetter} */
function getEffectUpdateData(effectData) {
const data = foundry.utils.deepClone(effectData);
let hasUpdates = false;
if ("changes" in data) {
for (const change of data.changes) {
const newValue = change.value.replaceAll(/@data\./g, "@system.");
if (newValue !== change.value) {
hasUpdates = true;
change.value = newValue;
}
}
}
/** @type {string | undefined} */
const condition = data.flags?.ds4?.itemEffectConfig?.condition;
if (condition !== undefined) {
const newCondition = condition.replaceAll(/(@actor|@item|@effect)\.data/g, "$1.system");
if (newCondition !== condition) {
hasUpdates = true;
data.flags.ds4.itemEffectConfig.condition = newCondition;
}
}
if (hasUpdates) {
return data;
}
}
const getItemUpdateData = getItemUpdateDataGetter(getEffectUpdateData);
const getActorUpdateData = getActorUpdateDataGetter(getItemUpdateData, getEffectUpdateData);
const getSceneUpdateData = getSceneUpdateDataGetter(getActorUpdateData);
const migrateCompendium = getCompendiumMigrator({ getItemUpdateData, getActorUpdateData, getSceneUpdateData });
/** @type {import("./migration").Migration} */
export const migration = {
migrate,
migrateCompendium,
};

View file

@ -12,6 +12,7 @@ import { migration as migration004 } from "./004";
import { migration as migration005 } from "./005"; import { migration as migration005 } from "./005";
import { migration as migration006 } from "./006"; import { migration as migration006 } from "./006";
import { migration as migration007 } from "./007"; import { migration as migration007 } from "./007";
import { migration as migration008 } from "./008";
/** /**
* Perform migrations. * Perform migrations.
@ -166,7 +167,16 @@ function getTargetMigrationVersion() {
/** /**
* @type {Migration[]} * @type {Migration[]}
*/ */
const migrations = [migration001, migration002, migration003, migration004, migration005, migration006, migration007]; const migrations = [
migration001,
migration002,
migration003,
migration004,
migration005,
migration006,
migration007,
migration008,
];
/** /**
* DOes the migration version indicate the world is being started for the first time? * DOes the migration version indicate the world is being started for the first time?

View file

@ -7,7 +7,9 @@ import { DS4Item } from "../documents/item/item";
import { logger } from "../utils/logger"; import { logger } from "../utils/logger";
import { getGame } from "../utils/utils"; import { getGame } from "../utils/utils";
/** @typedef {(itemData: Partial<foundry.data.ItemData["_source"]>) => DeepPartial<foundry.data.ItemData["_source"]> | Record<string, unknown> | undefined} ItemUpdateDataGetter */ /** @typedef {(effectData: object) => Record<string, unknown> | undefined} EffectUpdateDataGetter */
/** @typedef {(itemData: object) => Record<string, unknown> | undefined} ItemUpdateDataGetter */
/** /**
* Migrate world items. * Migrate world items.
@ -28,7 +30,7 @@ export async function migrateItems(getItemUpdateData) {
} }
} }
/** @typedef {(actorData: Partial<foundry.data.ActorData["_source"]>) => DeepPartial<foundry.data.ActorData["_source"]> | undefined} ActorUpdateDataGetter */ /** @typedef {(actorData: object>) => Record<string, unknown> | undefined} ActorUpdateDataGetter */
/** /**
* Migrate world actors. * Migrate world actors.
@ -52,7 +54,7 @@ export async function migrateActors(getActorUpdateData) {
} }
} }
/** @typedef {(aceneData: foundry.data.SceneData) => DeepPartial<foundry.data.SceneData["_source"]> | undefined} SceneUpdateDataGetter */ /** @typedef {(scene: Scene) => Record<string, unknown> | undefined} SceneUpdateDataGetter */
/** /**
* Migrate world scenes. * Migrate world scenes.
@ -62,10 +64,12 @@ export async function migrateActors(getActorUpdateData) {
export async function migrateScenes(getSceneUpdateData) { export async function migrateScenes(getSceneUpdateData) {
for (const scene of getGame().scenes ?? []) { for (const scene of getGame().scenes ?? []) {
try { try {
const updateData = getSceneUpdateData(scene.data); const updateData = getSceneUpdateData(scene);
if (updateData) { if (updateData) {
logger.info(`Migrating Scene document ${scene.name} (${scene.id})`); logger.info(`Migrating Scene document ${scene.name} (${scene.id})`);
await scene.update(updateData); await scene.update(updateData);
// We need to clear the old syntehtic actors from the cache
scene.tokens.forEach((t) => (t._actor = null));
} }
} catch (err) { } catch (err) {
logger.error( logger.error(
@ -76,7 +80,7 @@ export async function migrateScenes(getSceneUpdateData) {
} }
} }
/** @typedef {(pack: CompendiumCollection) => Promise<void>} CompendiumMigrator*/ /** @typedef {(pack: CompendiumCollection) => Promise<void>} CompendiumMigrator */
/** /**
* Migrate world compendium packs. * Migrate world compendium packs.
@ -92,34 +96,70 @@ export async function migrateCompendiums(migrateCompendium) {
} }
/** /**
* Get a function to create actor update data that adjusts the owned items of the actor according to the given function. * Get a function to create item update data based on the given function to update embedded documents.
* @param {ItemUpdateDataGetter} getItemUpdateData The function to generate item update data * @param {EffectUpdateDataGetter} [getEffectUpdateData] A function to generate effect update data
* @returns {ItemUpdateDataGetter} A function to get item update data
*/
export function getItemUpdateDataGetter(getEffectUpdateData) {
return (itemData) => {
let hasEffectUpdates = false;
const effects = itemData.effects?.map((effectData) => {
const update = getEffectUpdateData(effectData);
if (update) {
hasEffectUpdates = true;
return foundry.utils.mergeObject(effectData, update, { inplace: false, performDeletions: true });
} else {
return effectData;
}
});
return hasEffectUpdates ? { effects } : undefined;
};
}
/**
* Get a function to create actor update data based on the given function to update embedded documents.
* @param {ItemUpdateDataGetter} [getItemUpdateData] A function to generate item update data
* @param {EffectUpdateDataGetter} [getEffectUpdateData] A function to generate effect update data
* @returns {ActorUpdateDataGetter} A function to get actor update data * @returns {ActorUpdateDataGetter} A function to get actor update data
*/ */
export function getActorUpdateDataGetter(getItemUpdateData) { export function getActorUpdateDataGetter(getItemUpdateData, getEffectUpdateData) {
return (actorData) => { return (actorData) => {
let hasItemUpdates = false; let hasItemUpdates = false;
const items = actorData.items?.map((itemData) => { const items = actorData.items?.map((itemData) => {
const update = getItemUpdateData(itemData); const update = getItemUpdateData?.(itemData);
if (update) { if (update) {
hasItemUpdates = true; hasItemUpdates = true;
return { ...itemData, ...update }; return foundry.utils.mergeObject(itemData, update, { inplace: false, performDeletions: true });
} else { } else {
return itemData; return itemData;
} }
}); });
return hasItemUpdates ? { items } : undefined; let hasEffectUpdates = false;
const effects = actorData.effects?.map((effectData) => {
const update = getEffectUpdateData?.(effectData);
if (update) {
hasEffectUpdates = true;
return foundry.utils.mergeObject(effectData, update, { inplace: false, performDeletions: true });
} else {
return effectData;
}
});
const result = {
items: hasItemUpdates ? items : undefined,
effects: hasEffectUpdates ? effects : undefined,
};
return hasItemUpdates | hasEffectUpdates ? result : undefined;
}; };
} }
/** /**
* Get a function to create scene update data that adjusts the actors of the tokens of the scene according to the given function. * Get a function to create scene update data that adjusts the actors of the tokens of the scene according to the given function.
* @param {ActorUpdateDataGetter} getItemUpdateData The function to generate actor update data * @param {ActorUpdateDataGetter} [getItemUpdateData] The function to generate actor update data
* @returns {SceneUpdateDataGetter} A function to get scene update data * @returns {SceneUpdateDataGetter} A function to get scene update data
*/ */
export function getSceneUpdateDataGetter(getActorUpdateData) { export function getSceneUpdateDataGetter(getActorUpdateData) {
return (sceneData) => { return (scene) => {
const tokens = sceneData.tokens.map((token) => { const tokens = scene.tokens.map((token) => {
const t = token.toObject(); const t = token.toObject();
if (!t.actorId || t.actorLink) { if (!t.actorId || t.actorLink) {
t.actorData = {}; t.actorData = {};
@ -129,18 +169,18 @@ export function getSceneUpdateDataGetter(getActorUpdateData) {
} else if (!t.actorLink) { } else if (!t.actorLink) {
const actorData = foundry.utils.deepClone(t.actorData); const actorData = foundry.utils.deepClone(t.actorData);
actorData.type = token.actor?.type; actorData.type = token.actor?.type;
const update = getActorUpdateData(actorData); const update = getActorUpdateData?.(actorData);
if (update !== undefined) { if (update !== undefined) {
["items", "effects"].forEach((embeddedName) => { ["items", "effects"].forEach((embeddedName) => {
const embeddedUpdates = update[embeddedName]; const embeddedUpdates = update[embeddedName];
if (embeddedUpdates === undefined || !embeddedUpdates.length) return; if (!embeddedUpdates?.length) return;
const updates = new Map(embeddedUpdates.flatMap((u) => (u && u._id ? [[u._id, u]] : []))); const updates = new Map(embeddedUpdates.flatMap((u) => (u && u._id ? [[u._id, u]] : [])));
const originals = t.actorData[embeddedName]; const originals = t.actorData[embeddedName];
if (!originals) return; if (!originals) return;
originals.forEach((original) => { originals.forEach((original) => {
if (!original._id) return; if (!original._id) return;
const update = updates.get(original._id); const update = updates.get(original._id);
if (update) foundry.utils.mergeObject(original, update); if (update) foundry.utils.mergeObject(original, update, { performDeletions: true });
}); });
delete update[embeddedName]; delete update[embeddedName];
}); });
@ -191,7 +231,7 @@ export function getCompendiumMigrator(
const updateData = getActorUpdateData(doc.toObject()); const updateData = getActorUpdateData(doc.toObject());
updateData && (await doc.update(updateData)); updateData && (await doc.update(updateData));
} else if (doc instanceof Scene && getSceneUpdateData) { } else if (doc instanceof Scene && getSceneUpdateData) {
const updateData = getSceneUpdateData(doc.data); const updateData = getSceneUpdateData(doc);
updateData && (await doc.update(updateData)); updateData && (await doc.update(updateData));
} }
} catch (err) { } catch (err) {

View file

@ -1,5 +1,5 @@
{ {
"name": "ds4", "id": "ds4",
"title": "Dungeonslayers 4", "title": "Dungeonslayers 4",
"description": "An implementation of the <a href='https://www.dungeonslayers.net'>Dungeonslayers</a> 4 game system for Foundry Virtual Tabletop.", "description": "An implementation of the <a href='https://www.dungeonslayers.net'>Dungeonslayers</a> 4 game system for Foundry Virtual Tabletop.",
"authors": [ "authors": [
@ -34,8 +34,10 @@
"bugs": "https://git.f3l.de/dungeonslayers/ds4/-/issues", "bugs": "https://git.f3l.de/dungeonslayers/ds4/-/issues",
"changelog": "https://git.f3l.de/dungeonslayers/ds4/-/releases/v1.18.2", "changelog": "https://git.f3l.de/dungeonslayers/ds4/-/releases/v1.18.2",
"version": "1.18.2", "version": "1.18.2",
"minimumCoreVersion": "9.238", "compatibility": {
"compatibleCoreVersion": "9", "minimum": "10.290",
"verified": "10"
},
"esmodules": ["ds4.js"], "esmodules": ["ds4.js"],
"styles": ["css/ds4.css"], "styles": ["css/ds4.css"],
"languages": [ "languages": [

View file

@ -8,40 +8,41 @@ SPDX-License-Identifier: MIT
<div class="ds4-actor-progression"> <div class="ds4-actor-progression">
<div class="ds4-actor-progression__entry"> <div class="ds4-actor-progression__entry">
<h2 class="ds4-actor-progression__label"><label for="data.combatValues.hitPoints.value-{{data._id}}" <h2 class="ds4-actor-progression__label"><label for="system.combatValues.hitPoints.value-{{data._id}}"
title="{{localize 'DS4.CombatValuesHitPointsCurrent'}}">{{localize title="{{localize 'DS4.CombatValuesHitPointsCurrent'}}">{{localize
"DS4.CombatValuesHitPointsCurrentAbbr"}}</label> "DS4.CombatValuesHitPointsCurrentAbbr"}}</label>
</h2> </h2>
<input class="ds4-actor-progression__input" type="number" name="data.combatValues.hitPoints.value" <input class="ds4-actor-progression__input" type="number" name="system.combatValues.hitPoints.value"
id="data.combatValues.hitPoints.value-{{data._id}}" value="{{data.data.combatValues.hitPoints.value}}" id="system.combatValues.hitPoints.value-{{data._id}}" value="{{data.system.combatValues.hitPoints.value}}"
data-dtype="Number" /> data-dtype="Number" />
</div> </div>
{{#if (eq data.type "character")}} {{#if (eq data.type "character")}}
{{#if settings.showSlayerPoints}} {{#if settings.showSlayerPoints}}
<div class="ds4-actor-progression__entry"> <div class="ds4-actor-progression__entry">
<h2 class="ds4-actor-progression__label"><label for="data.slayersPoints.value-{{data._id}}" <h2 class="ds4-actor-progression__label"><label for="system.slayersPoints.value-{{data._id}}"
title="{{localize 'DS4.CharacterSlayerPoints'}}">{{localize "DS4.CharacterSlayerPointsAbbr"}}</label> title="{{localize 'DS4.CharacterSlayerPoints'}}">{{localize "DS4.CharacterSlayerPointsAbbr"}}</label>
</h2> </h2>
<input class="ds4-actor-progression__input ds4-actor-progression__input--slayer-points" type="number" <input class="ds4-actor-progression__input ds4-actor-progression__input--slayer-points" type="number"
max="{{data.data.slayerPoints.max}}" min="0" step="1" name="data.slayerPoints.value" max="{{data.system.slayerPoints.max}}" min="0" step="1" name="system.slayerPoints.value"
id="data.slayersPoints.value-{{data._id}}" value="{{data.data.slayerPoints.value}}" data-dtype="Number" /> id="system.slayersPoints.value-{{data._id}}" value="{{data.system.slayerPoints.value}}"
data-dtype="Number" />
</div> </div>
{{/if}} {{/if}}
<div class="ds4-actor-progression__entry"> <div class="ds4-actor-progression__entry">
<h2 class="ds4-actor-progression__label"><label for="data.progression.level-{{data._id}}" <h2 class="ds4-actor-progression__label"><label for="system.progression.level-{{data._id}}"
title="{{localize 'DS4.CharacterProgressionLevel'}}">{{localize title="{{localize 'DS4.CharacterProgressionLevel'}}">{{localize
"DS4.CharacterProgressionLevelAbbr"}}</label> "DS4.CharacterProgressionLevelAbbr"}}</label>
</h2> </h2>
<input class="ds4-actor-progression__input" type="number" min="0" name="data.progression.level" <input class="ds4-actor-progression__input" type="number" min="0" name="system.progression.level"
id="data.progression.level-{{data._id}}" value="{{data.data.progression.level}}" data-dtype="Number" /> id="system.progression.level-{{data._id}}" value="{{data.system.progression.level}}" data-dtype="Number" />
</div> </div>
<div class="ds4-actor-progression__entry"> <div class="ds4-actor-progression__entry">
<h2 class="ds4-actor-progression__label"><label for="data.progression.experiencePoints-{{data._id}}" <h2 class="ds4-actor-progression__label"><label for="system.progression.experiencePoints-{{data._id}}"
title="{{localize 'DS4.CharacterProgressionExperiencePoints'}}">{{localize title="{{localize 'DS4.CharacterProgressionExperiencePoints'}}">{{localize
"DS4.CharacterProgressionExperiencePointsAbbr"}}</label> "DS4.CharacterProgressionExperiencePointsAbbr"}}</label>
</h2> </h2>
<input class="ds4-actor-progression__input" type="number" min="0" name="data.progression.experiencePoints" <input class="ds4-actor-progression__input" type="number" min="0" name="system.progression.experiencePoints"
id="data.progression.experiencePoints-{{data._id}}" value="{{data.data.progression.experiencePoints}}" id="system.progression.experiencePoints-{{data._id}}" value="{{data.system.progression.experiencePoints}}"
data-dtype="Number" /> data-dtype="Number" />
</div> </div>
{{/if}} {{/if}}

View file

@ -5,6 +5,6 @@ SPDX-License-Identifier: MIT
--}} --}}
<div class="ds4-biography"> <div class="ds4-biography">
{{editor content=data.data.profile.biography target="data.profile.biography" button=true owner=owner {{editor data.system.profile.biography target="system.profile.biography" button=true owner=owner
editable=editable}} editable=editable engine="prosemirror"}}
</div> </div>

View file

@ -9,55 +9,56 @@ SPDX-License-Identifier: MIT
<div class="ds4-actor-properties"> <div class="ds4-actor-properties">
<div class="ds4-actor-properties__property"> <div class="ds4-actor-properties__property">
<label class="ds4-actor-properties__property-label" <label class="ds4-actor-properties__property-label"
for="data.baseInfo.race-{{data._id}}">{{config.i18n.characterBaseInfo.race}}</label> for="system.baseInfo.race-{{data._id}}">{{config.i18n.characterBaseInfo.race}}</label>
<input type="text" name="data.baseInfo.race" id="data.baseInfo.race-{{data._id}}" <input type="text" name="system.baseInfo.race" id="system.baseInfo.race-{{data._id}}"
value="{{data.data.baseInfo.race}}" data-dtype="String" /> value="{{data.system.baseInfo.race}}" data-dtype="String" />
</div> </div>
<div class="ds4-actor-properties__property"> <div class="ds4-actor-properties__property">
<label class="ds4-actor-properties__property-label" <label class="ds4-actor-properties__property-label"
for="data.baseInfo.culture-{{data._id}}">{{config.i18n.characterBaseInfo.culture}}</label> for="system.baseInfo.culture-{{data._id}}">{{config.i18n.characterBaseInfo.culture}}</label>
<input id="data.baseInfo.culture-{{data._id}}" type="text" name="data.baseInfo.culture" <input id="system.baseInfo.culture-{{data._id}}" type="text" name="system.baseInfo.culture"
value="{{data.data.baseInfo.culture}}" data-dtype="String" /> value="{{data.system.baseInfo.culture}}" data-dtype="String" />
</div> </div>
<div class="ds4-actor-properties__property"> <div class="ds4-actor-properties__property">
<label class="ds4-actor-properties__property-label" <label class="ds4-actor-properties__property-label"
for="data.progression.progressPoints.used-{{data._id}}">{{config.i18n.characterProgression.progressPoints}}</label> for="system.progression.progressPoints.used-{{data._id}}">{{config.i18n.characterProgression.progressPoints}}</label>
<div class="ds4-actor-properties__property-multi-input"> <div class="ds4-actor-properties__property-multi-input">
<input id="data.progression.progressPoints.used-{{data._id}}" type="number" <input id="system.progression.progressPoints.used-{{data._id}}" type="number"
name="data.progression.progressPoints.used" value="{{data.data.progression.progressPoints.used}}" name="system.progression.progressPoints.used" value="{{data.system.progression.progressPoints.used}}"
data-dtype="Number" /> data-dtype="Number" />
<span class="input-divider"> / </span> <span class="input-divider"> / </span>
<label class="ds4-hidden" for="data.progression.progressPoints.total-{{data._id}}">Total <label class="ds4-hidden" for="system.progression.progressPoints.total-{{data._id}}">Total
Progression Points</label> Progression Points</label>
<input type="number" id="data.progression.progressPoints.total-{{data._id}}" <input type="number" id="system.progression.progressPoints.total-{{data._id}}"
name="data.progression.progressPoints.total" value="{{data.data.progression.progressPoints.total}}" name="system.progression.progressPoints.total" value="{{data.system.progression.progressPoints.total}}"
data-dtype="Number" /> data-dtype="Number" />
</div> </div>
</div> </div>
<div class="ds4-actor-properties__property"> <div class="ds4-actor-properties__property">
<label class="ds4-actor-properties__property-label" <label class="ds4-actor-properties__property-label"
for="data.progression.talentPoints.used-{{data._id}}">{{config.i18n.characterProgression.talentPoints}}</label> for="system.progression.talentPoints.used-{{data._id}}">{{config.i18n.characterProgression.talentPoints}}</label>
<div class="ds4-actor-properties__property-multi-input"> <div class="ds4-actor-properties__property-multi-input">
<input type="number" name="data.progression.talentPoints.used" <input type="number" name="system.progression.talentPoints.used"
id="data.progression.talentPoints.used-{{data._id}}" value="{{data.data.progression.talentPoints.used}}" id="system.progression.talentPoints.used-{{data._id}}"
data-dtype="Number" /> value="{{data.system.progression.talentPoints.used}}" data-dtype="Number" />
<span class="input-divider"> / </span> <span class="input-divider"> / </span>
<label for="data.progression.talentPoints.total-{{data._id}}" class="ds4-hidden">Total Talent Points</label> <label for="system.progression.talentPoints.total-{{data._id}}" class="ds4-hidden">Total Talent
<input type="number" name="data.progression.talentPoints.total" Points</label>
id="data.progression.talentPoints.total-{{data._id}}" <input type="number" name="system.progression.talentPoints.total"
value="{{data.data.progression.talentPoints.total}}" data-dtype="Number" /> id="system.progression.talentPoints.total-{{data._id}}"
value="{{data.system.progression.talentPoints.total}}" data-dtype="Number" />
</div> </div>
</div> </div>
<div class="ds4-actor-properties__property"> <div class="ds4-actor-properties__property">
<label class="ds4-actor-properties__property-label" <label class="ds4-actor-properties__property-label"
for="data.baseInfo.class-{{data._id}}">{{config.i18n.characterBaseInfo.class}}</label> for="system.baseInfo.class-{{data._id}}">{{config.i18n.characterBaseInfo.class}}</label>
<input type="text" id="data.baseInfo.class-{{data._id}}" name="data.baseInfo.class" <input type="text" id="system.baseInfo.class-{{data._id}}" name="system.baseInfo.class"
value="{{data.data.baseInfo.class}}" data-dtype="String" /> value="{{data.system.baseInfo.class}}" data-dtype="String" />
</div> </div>
<div class="ds4-actor-properties__property"> <div class="ds4-actor-properties__property">
<label class="ds4-actor-properties__property-label" <label class="ds4-actor-properties__property-label"
for="data.baseInfo.heroClass-{{data._id}}">{{config.i18n.characterBaseInfo.heroClass}}</label> for="system.baseInfo.heroClass-{{data._id}}">{{config.i18n.characterBaseInfo.heroClass}}</label>
<input type="text" id="data.baseInfo.heroClass-{{data._id}}" name="data.baseInfo.heroClass" <input type="text" id="system.baseInfo.heroClass-{{data._id}}" name="system.baseInfo.heroClass"
value="{{data.data.baseInfo.heroClass}}" data-dtype="String" /> value="{{data.system.baseInfo.heroClass}}" data-dtype="String" />
</div> </div>
</div> </div>

View file

@ -7,6 +7,6 @@ SPDX-License-Identifier: MIT
<div class="ds4-checks"> <div class="ds4-checks">
{{#each config.i18n.checks as |check-label check-key|}} {{#each config.i18n.checks as |check-label check-key|}}
{{> systems/ds4/templates/sheets/actor/components/check.hbs check-key=check-key check-target-number=(lookup {{> systems/ds4/templates/sheets/actor/components/check.hbs check-key=check-key check-target-number=(lookup
../data.data.checks check-key) check-label=check-label}} ../data.system.checks check-key) check-label=check-label}}
{{/each}} {{/each}}
</div> </div>

View file

@ -25,8 +25,8 @@ SPDX-License-Identifier: MIT
title="{{combat-value-title}} {{localize 'DS4.TooltipBaseValue'}}">{{combat-value-data.base}}</span> title="{{combat-value-title}} {{localize 'DS4.TooltipBaseValue'}}">{{combat-value-data.base}}</span>
<span>+</span> <span>+</span>
<input class="ds4-combat-value__formula-modifier" type="number" <input class="ds4-combat-value__formula-modifier" type="number"
id="data.combatValues.{{combat-value-key}}.mod-{{actor-id}}" id="system.combatValues.{{combat-value-key}}.mod-{{actor-id}}"
name="data.combatValues.{{combat-value-key}}.mod" value='{{combat-value-data.mod}}' data-dtype="Number" name="system.combatValues.{{combat-value-key}}.mod" value='{{combat-value-data.mod}}' data-dtype="Number"
title="{{combat-value-title}} {{localize 'DS4.TooltipModifier'}}" /> title="{{combat-value-title}} {{localize 'DS4.TooltipModifier'}}" />
</div> </div>
</div> </div>

View file

@ -8,7 +8,7 @@ SPDX-License-Identifier: MIT
<div class="ds4-combat-values"> <div class="ds4-combat-values">
{{#each config.i18n.combatValues as |combat-value-title combat-value-key|}} {{#each config.i18n.combatValues as |combat-value-title combat-value-key|}}
{{> systems/ds4/templates/sheets/actor/components/combat-value.hbs combat-value-key=combat-value-key {{> systems/ds4/templates/sheets/actor/components/combat-value.hbs combat-value-key=combat-value-key
combat-value-data=(lookup ../data.data.combatValues combat-value-key) combat-value-label=(lookup combat-value-data=(lookup ../data.system.combatValues combat-value-key) combat-value-label=(lookup
../config.i18n.combatValuesSheet combat-value-key) combat-value-title=combat-value-title ../config.i18n.combatValuesSheet combat-value-key) combat-value-title=combat-value-title
actor-id=../data._id}} actor-id=../data._id}}
{{/each}} {{/each}}

View file

@ -15,17 +15,17 @@ SPDX-License-Identifier: MIT
--}} --}}
<div class="ds4-core-value ds4-core-value--{{core-value-variant}}"> <div class="ds4-core-value ds4-core-value--{{core-value-variant}}">
<label for="data.{{core-value-variant}}s.{{core-value-key}}.base-{{actor-id}}" <label for="system.{{core-value-variant}}s.{{core-value-key}}.base-{{actor-id}}"
class="ds4-core-value__label">{{core-value-label}}</label> class="ds4-core-value__label">{{core-value-label}}</label>
<div class="ds4-core-value__value"> <div class="ds4-core-value__value">
<input class="ds4-core-value__value-input" type="number" <input class="ds4-core-value__value-input" type="number"
name="data.{{core-value-variant}}s.{{core-value-key}}.base" name="system.{{core-value-variant}}s.{{core-value-key}}.base"
id="data.{{core-value-variant}}s.{{core-value-key}}.base-{{actor-id}}" value='{{core-value-data.base}}' id="system.{{core-value-variant}}s.{{core-value-key}}.base-{{actor-id}}" value='{{core-value-data.base}}'
data-dtype="Number" title="{{core-value-label}} {{localize 'DS4.TooltipBaseValue'}}" /> data-dtype="Number" title="{{core-value-label}} {{localize 'DS4.TooltipBaseValue'}}" />
<span>+</span> <span>+</span>
<input class="ds4-core-value__value-input" type="number" <input class="ds4-core-value__value-input" type="number"
name="data.{{core-value-variant}}s.{{core-value-key}}.mod" name="system.{{core-value-variant}}s.{{core-value-key}}.mod"
id="data.{{core-value-variant}}s.{{core-value-key}}.mod-{{actor-id}}" value='{{core-value-data.mod}}' id="system.{{core-value-variant}}s.{{core-value-key}}.mod-{{actor-id}}" value='{{core-value-data.mod}}'
data-dtype="Number" title="{{core-value-label}} {{localize 'DS4.TooltipModifier'}}" /> data-dtype="Number" title="{{core-value-label}} {{localize 'DS4.TooltipModifier'}}" />
<span class="ds4-core-value__value-arrow">➞</span> <span class="ds4-core-value__value-arrow">➞</span>
<span class="ds4-core-value__value-total" <span class="ds4-core-value__value-total"

View file

@ -8,12 +8,12 @@ SPDX-License-Identifier: MIT
<div class="ds4-core-values"> <div class="ds4-core-values">
{{#each config.i18n.attributes as |attribute-label attribute-key|}} {{#each config.i18n.attributes as |attribute-label attribute-key|}}
{{> systems/ds4/templates/sheets/actor/components/core-value.hbs core-value-label=attribute-label {{> systems/ds4/templates/sheets/actor/components/core-value.hbs core-value-label=attribute-label
core-value-key=attribute-key core-value-data=(lookup ../data.data.attributes core-value-key=attribute-key core-value-data=(lookup ../data.system.attributes
attribute-key) core-value-variant="attribute" actor-id=../data._id}} attribute-key) core-value-variant="attribute" actor-id=../data._id}}
{{/each}} {{/each}}
{{#each config.i18n.traits as |trait-label trait-key|}} {{#each config.i18n.traits as |trait-label trait-key|}}
{{> systems/ds4/templates/sheets/actor/components/core-value.hbs core-value-label=trait-label {{> systems/ds4/templates/sheets/actor/components/core-value.hbs core-value-label=trait-label
core-value-key=trait-key core-value-key=trait-key
core-value-data=(lookup ../data.data.traits trait-key) core-value-variant="trait" actor-id=../data._id}} core-value-data=(lookup ../data.system.traits trait-key) core-value-variant="trait" actor-id=../data._id}}
{{/each}} {{/each}}
</div> </div>

View file

@ -9,10 +9,10 @@ SPDX-License-Identifier: MIT
<div class="ds4-actor-properties"> <div class="ds4-actor-properties">
<div class="ds4-actor-properties__property"> <div class="ds4-actor-properties__property">
<label class="ds4-actor-properties__property-label" <label class="ds4-actor-properties__property-label"
for="data.baseInfo.creatureType-{{data._id}}">{{config.i18n.creatureBaseInfo.creatureType}}</label> for="system.baseInfo.creatureType-{{data._id}}">{{config.i18n.creatureBaseInfo.creatureType}}</label>
<select class="ds4-actor-properties__property-select" id="data.baseInfo.creatureType-{{data._id}}" <select class="ds4-actor-properties__property-select" id="system.baseInfo.creatureType-{{data._id}}"
name="data.baseInfo.creatureType" data-dtype="String"> name="system.baseInfo.creatureType" data-dtype="String">
{{#select data.data.baseInfo.creatureType}} {{#select data.system.baseInfo.creatureType}}
{{#each config.i18n.creatureTypes as |value key|}} {{#each config.i18n.creatureTypes as |value key|}}
<option value="{{key}}">{{value}}</option> <option value="{{key}}">{{value}}</option>
{{/each}} {{/each}}
@ -21,22 +21,22 @@ SPDX-License-Identifier: MIT
</div> </div>
<div class="ds4-actor-properties__property"> <div class="ds4-actor-properties__property">
<label class="ds4-actor-properties__property-label" <label class="ds4-actor-properties__property-label"
for="data.baseInfo.loot-{{data._id}}">{{config.i18n.creatureBaseInfo.loot}}</label> for="system.baseInfo.loot-{{data._id}}">{{config.i18n.creatureBaseInfo.loot}}</label>
<input type="text" id="data.baseInfo.loot-{{data._id}}" name="data.baseInfo.loot" <input type="text" id="system.baseInfo.loot-{{data._id}}" name="system.baseInfo.loot"
value="{{data.data.baseInfo.loot}}" data-dtype="String" /> value="{{data.system.baseInfo.loot}}" data-dtype="String" />
</div> </div>
<div class="ds4-actor-properties__property"> <div class="ds4-actor-properties__property">
<label class="ds4-actor-properties__property-label" <label class="ds4-actor-properties__property-label"
for="data.baseInfo.foeFactor-{{data._id}}">{{config.i18n.creatureBaseInfo.foeFactor}}</label> for="system.baseInfo.foeFactor-{{data._id}}">{{config.i18n.creatureBaseInfo.foeFactor}}</label>
<input type="text" id="data.baseInfo.foeFactor-{{data._id}}" name="data.baseInfo.foeFactor" <input type="text" id="system.baseInfo.foeFactor-{{data._id}}" name="system.baseInfo.foeFactor"
value="{{data.data.baseInfo.foeFactor}}" data-dtype="Number" /> value="{{data.system.baseInfo.foeFactor}}" data-dtype="Number" />
</div> </div>
<div class="ds4-actor-properties__property"> <div class="ds4-actor-properties__property">
<label class="ds4-actor-properties__property-label" <label class="ds4-actor-properties__property-label"
for="data.baseInfo.sizeCategory-{{data._id}}">{{config.i18n.creatureBaseInfo.sizeCategory}}</label> for="system.baseInfo.sizeCategory-{{data._id}}">{{config.i18n.creatureBaseInfo.sizeCategory}}</label>
<select class="ds4-actor-properties__property-select" id="data.baseInfo.sizeCategory-{{data._id}}" <select class="ds4-actor-properties__property-select" id="system.baseInfo.sizeCategory-{{data._id}}"
name="data.baseInfo.sizeCategory" data-dtype="String"> name="system.baseInfo.sizeCategory" data-dtype="String">
{{#select data.data.baseInfo.sizeCategory}} {{#select data.system.baseInfo.sizeCategory}}
{{#each config.i18n.creatureSizeCategories as |value key|}} {{#each config.i18n.creatureSizeCategories as |value key|}}
<option value="{{key}}">{{value}}</option> <option value="{{key}}">{{value}}</option>
{{/each}} {{/each}}
@ -45,8 +45,8 @@ SPDX-License-Identifier: MIT
</div> </div>
<div class="ds4-actor-properties__property"> <div class="ds4-actor-properties__property">
<label class="ds4-actor-properties__property-label" <label class="ds4-actor-properties__property-label"
for="data.baseInfo.experiencePoints-{{data._id}}">{{config.i18n.creatureBaseInfo.experiencePoints}}</label> for="system.baseInfo.experiencePoints-{{data._id}}">{{config.i18n.creatureBaseInfo.experiencePoints}}</label>
<input type="text" id="data.baseInfo.experiencePoints-{{data._id}}" name="data.baseInfo.experiencePoints" <input type="text" id="system.baseInfo.experiencePoints-{{data._id}}" name="system.baseInfo.experiencePoints"
value="{{data.data.baseInfo.experiencePoints}}" data-dtype="Number" /> value="{{data.system.baseInfo.experiencePoints}}" data-dtype="Number" />
</div> </div>
</div> </div>

View file

@ -8,9 +8,9 @@ SPDX-License-Identifier: MIT
<h4 class="ds4-currency-title">{{localize 'DS4.CharacterCurrency'}}</h4> <h4 class="ds4-currency-title">{{localize 'DS4.CharacterCurrency'}}</h4>
<div class="ds4-currency"> <div class="ds4-currency">
{{#each data.data.currency as |value key|}} {{#each data.system.currency as |value key|}}
<label for="data.currency.{{key}}" class="flex05">{{lookup ../config.i18n.characterCurrency key}}</label> <label for="system.currency.{{key}}" class="flex05">{{lookup ../config.i18n.characterCurrency key}}</label>
<input class="ds4-currency__value ds4-currency__value--{{key}}" type="number" min="0" step="1" <input class="ds4-currency__value ds4-currency__value--{{key}}" type="number" min="0" step="1"
name="data.currency.{{key}}" id="data.currency.{{key}}" value="{{value}}" data-dtype="Number" /> name="system.currency.{{key}}" id="system.currency.{{key}}" value="{{value}}" data-dtype="Number" />
{{/each}} {{/each}}
</div> </div>

View file

@ -5,6 +5,6 @@ SPDX-License-Identifier: MIT
--}} --}}
<div class="ds4-description"> <div class="ds4-description">
{{editor content=data.data.baseInfo.description target="data.baseInfo.description" button=true owner=owner {{editor data.system.baseInfo.description target="system.baseInfo.description" button=true owner=owner
editable=editable}} editable=editable engine="prosemirror"}}
</div> </div>

View file

@ -19,24 +19,24 @@ SPDX-License-Identifier: MIT
{{!-- equipped --}} {{!-- equipped --}}
{{#if isEquipable}} {{#if isEquipable}}
<input class="ds4-embedded-document-list__editable ds4-embedded-document-list__editable--checkbox change-item" type="checkbox" {{checked <input class="ds4-embedded-document-list__editable ds4-embedded-document-list__editable--checkbox change-item" type="checkbox" {{checked
itemData.data.equipped}} data-dtype="Boolean" data-property="data.equipped" itemData.system.equipped}} data-dtype="Boolean" data-property="system.equipped"
title="{{localize 'DS4.ItemEquipped'}}"> title="{{localize 'DS4.ItemEquipped'}}">
{{/if}} {{/if}}
{{!-- image --}} {{!-- image --}}
{{> systems/ds4/templates/sheets/shared/components/rollable-image.hbs rollable=(and itemData.data.rollable @root/editable) {{> systems/ds4/templates/sheets/shared/components/rollable-image.hbs rollable=(and itemData.system.rollable @root/editable)
src=itemData.img alt=(localize "DS4.DocumentImageAltText" name=itemData.name) title=itemData.name src=itemData.img alt=(localize "DS4.DocumentImageAltText" name=itemData.name) title=itemData.name
rollableTitle=(localize "DS4.RollableImageRollableTitle" name=itemData.name) rollableClass="rollable-item"}} rollableTitle=(localize "DS4.RollableImageRollableTitle" name=itemData.name) rollableClass="rollable-item"}}
{{!-- amount --}} {{!-- amount --}}
{{#if hasQuantity}} {{#if hasQuantity}}
<input class="ds4-embedded-document-list__editable change-item" type="number" min="0" step="1" value="{{itemData.data.quantity}}" <input class="ds4-embedded-document-list__editable change-item" type="number" min="0" step="1" value="{{itemData.system.quantity}}"
data-dtype="Number" data-property="data.quantity" title="{{localize 'DS4.Quantity'}}" /> data-dtype="Number" data-property="system.quantity" title="{{localize 'DS4.Quantity'}}" />
{{/if}} {{/if}}
{{!-- name --}} {{!-- name --}}
<input class="ds4-embedded-document-list__editable change-item" type="text" value="{{itemData.name}}" data-dtype="String" <input class="ds4-embedded-document-list__editable change-item" type="text" value="{{itemData.name}}" data-dtype="String"
data-property="name" title="{{htmlToPlainText itemData.data.description}}" /> data-property="name" title="{{htmlToPlainText itemData.system.description}}" />
{{!-- item type specifics --}} {{!-- item type specifics --}}
{{#if @partial-block }} {{#if @partial-block }}
@ -45,8 +45,8 @@ SPDX-License-Identifier: MIT
{{!-- description --}} {{!-- description --}}
{{#unless hideDescription}} {{#unless hideDescription}}
<div class="ds4-embedded-document-list__description" title="{{htmlToPlainText itemData.data.description}}"> <div class="ds4-embedded-document-list__description" title="{{htmlToPlainText itemData.system.description}}">
{{{itemData.data.description}}}</div> {{{itemData.system.description}}}</div>
{{/unless}} {{/unless}}
{{!-- control button group --}} {{!-- control button group --}}

View file

@ -18,7 +18,7 @@ SPDX-License-Identifier: MIT
<li class="ds4-embedded-document-list__row ds4-embedded-document-list__row--header" data-type={{type}}> <li class="ds4-embedded-document-list__row ds4-embedded-document-list__row--header" data-type={{type}}>
{{!-- equipped --}} {{!-- equipped --}}
{{#if isEquipable}} {{#if isEquipable}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="data.equipped" <div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.equipped"
title="{{localize 'DS4.SortByItemEquipped'}}"> title="{{localize 'DS4.SortByItemEquipped'}}">
{{localize 'DS4.ItemEquippedAbbr'}}</div> {{localize 'DS4.ItemEquippedAbbr'}}</div>
{{/if}} {{/if}}
@ -28,7 +28,7 @@ SPDX-License-Identifier: MIT
{{!-- amount --}} {{!-- amount --}}
{{#if hasQuantity}} {{#if hasQuantity}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="data.quantity" <div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.quantity"
title="{{localize 'DS4.SortByQuantity'}}">#</div> title="{{localize 'DS4.SortByQuantity'}}">#</div>
{{/if}} {{/if}}
@ -44,7 +44,7 @@ SPDX-License-Identifier: MIT
{{!-- description --}} {{!-- description --}}
{{#unless hideDescription}} {{#unless hideDescription}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="data.description" <div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.description"
title="{{localize 'DS4.SortByDescription'}}">{{localize title="{{localize 'DS4.SortByDescription'}}">{{localize
'DS4.Description'}}</div> 'DS4.Description'}}</div>
{{/unless}} {{/unless}}

View file

@ -13,19 +13,19 @@ SPDX-License-Identifier: MIT
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true
type='weapon'}} type='weapon'}}
{{!-- attack type --}} {{!-- attack type --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="data.attackType" <div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.attackType"
title="{{localize 'DS4.SortByAttackType'}}"> title="{{localize 'DS4.SortByAttackType'}}">
{{localize {{localize
'DS4.AttackTypeAbbr'}}</div> 'DS4.AttackTypeAbbr'}}</div>
{{!-- weapon bonus --}} {{!-- weapon bonus --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="data.weaponBonus" <div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.weaponBonus"
title="{{localize 'DS4.SortByWeaponBonus'}}"> title="{{localize 'DS4.SortByWeaponBonus'}}">
{{localize 'DS4.WeaponBonusAbbr'}} {{localize 'DS4.WeaponBonusAbbr'}}
</div> </div>
{{!-- opponent defense --}} {{!-- opponent defense --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="data.opponentDefense" <div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.opponentDefense"
title="{{localize 'DS4.SortByOpponentDefense'}}"> title="{{localize 'DS4.SortByOpponentDefense'}}">
{{localize 'DS4.OpponentDefenseAbbr'}} {{localize 'DS4.OpponentDefenseAbbr'}}
</div> </div>
@ -36,24 +36,24 @@ SPDX-License-Identifier: MIT
hasQuantity=true}} hasQuantity=true}}
{{!-- attack type --}} {{!-- attack type --}}
<img class="ds4-embedded-document-list__image" <img class="ds4-embedded-document-list__image"
src="{{lookup @root/config.icons.attackTypes itemData.data.attackType}}" src="{{lookup @root/config.icons.attackTypes itemData.system.attackType}}"
title="{{lookup @root/config.i18n.attackTypes itemData.data.attackType}}" /> title="{{lookup @root/config.i18n.attackTypes itemData.system.attackType}}" />
{{!-- weapon bonus --}} {{!-- weapon bonus --}}
<div>{{ itemData.data.weaponBonus}}</div> <div>{{ itemData.system.weaponBonus}}</div>
{{!-- opponent defense --}} {{!-- opponent defense --}}
<div> <div>
{{#if itemData.data.opponentDefenseForAttackType.melee includeZero=true}} {{#if itemData.system.opponentDefenseForAttackType.melee includeZero=true}}
{{#if itemData.data.opponentDefenseForAttackType.ranged includeZero=true}} {{#if itemData.system.opponentDefenseForAttackType.ranged includeZero=true}}
<span <span
title="{{localize 'DS4.OpponentDefenseMelee'}}">{{itemData.data.opponentDefenseForAttackType.melee}}</span>/<span title="{{localize 'DS4.OpponentDefenseMelee'}}">{{itemData.system.opponentDefenseForAttackType.melee}}</span>/<span
title="{{localize 'DS4.OpponentDefenseRanged'}}">{{itemData.data.opponentDefenseForAttackType.ranged}}</span> title="{{localize 'DS4.OpponentDefenseRanged'}}">{{itemData.system.opponentDefenseForAttackType.ranged}}</span>
{{else}} {{else}}
{{itemData.data.opponentDefenseForAttackType.melee}} {{itemData.system.opponentDefenseForAttackType.melee}}
{{/if}} {{/if}}
{{else}} {{else}}
{{itemData.data.opponentDefenseForAttackType.ranged}} {{itemData.system.opponentDefenseForAttackType.ranged}}
{{/if}} {{/if}}
</div> </div>
{{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}} {{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}}
@ -70,15 +70,15 @@ documentType='item' type='weapon'}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true
type="armor"}} type="armor"}}
{{!-- armor material type --}} {{!-- armor material type --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="data.armorMaterialType" <div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.armorMaterialType"
title="{{localize 'DS4.SortByArmorMaterialType'}}">{{localize 'DS4.ArmorMaterialTypeAbbr'}}</div> title="{{localize 'DS4.SortByArmorMaterialType'}}">{{localize 'DS4.ArmorMaterialTypeAbbr'}}</div>
{{!-- armor type --}} {{!-- armor type --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="data.armorType" <div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.armorType"
title="{{localize 'DS4.SortByArmorType'}}">{{localize 'DS4.ArmorTypeAbbr'}}</div> title="{{localize 'DS4.SortByArmorType'}}">{{localize 'DS4.ArmorTypeAbbr'}}</div>
{{!-- armor value --}} {{!-- armor value --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="data.armorValue" <div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.armorValue"
title="{{localize 'DS4.SortByArmorValue'}}"> title="{{localize 'DS4.SortByArmorValue'}}">
{{localize 'DS4.ArmorValueAbbr'}} {{localize 'DS4.ArmorValueAbbr'}}
</div> </div>
@ -88,17 +88,17 @@ documentType='item' type='weapon'}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData isEquipable=true {{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData isEquipable=true
hasQuantity=true}} hasQuantity=true}}
{{!-- armor material type --}} {{!-- armor material type --}}
<div title="{{lookup @root/config.i18n.armorMaterialTypes itemData.data.armorMaterialType}}"> <div title="{{lookup @root/config.i18n.armorMaterialTypes itemData.system.armorMaterialType}}">
{{lookup @root/config.i18n.armorMaterialTypesAbbr itemData.data.armorMaterialType}} {{lookup @root/config.i18n.armorMaterialTypesAbbr itemData.system.armorMaterialType}}
</div> </div>
{{!-- armor type --}} {{!-- armor type --}}
<div title="{{lookup @root/config.i18n.armorTypes itemData.data.armorType}}"> <div title="{{lookup @root/config.i18n.armorTypes itemData.system.armorType}}">
{{lookup @root/config.i18n.armorTypesAbbr itemData.data.armorType}} {{lookup @root/config.i18n.armorTypesAbbr itemData.system.armorType}}
</div> </div>
{{!-- armor value --}} {{!-- armor value --}}
<div>{{ itemData.data.armorValue}}</div> <div>{{ itemData.system.armorValue}}</div>
{{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}} {{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}}
{{/each}} {{/each}}
</ol> </ol>
@ -113,7 +113,7 @@ documentType='item' type='armor'}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true
type='shield'}} type='shield'}}
{{!-- armor value --}} {{!-- armor value --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="data.armorValue" <div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.armorValue"
title="{{localize 'DS4.SortByArmorValue'}}"> title="{{localize 'DS4.SortByArmorValue'}}">
{{localize 'DS4.ArmorValueAbbr'}} {{localize 'DS4.ArmorValueAbbr'}}
</div> </div>
@ -122,7 +122,7 @@ documentType='item' type='armor'}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData isEquipable=true {{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData isEquipable=true
hasQuantity=true}} hasQuantity=true}}
{{!-- armor value --}} {{!-- armor value --}}
<div>{{itemData.data.armorValue}}</div> <div>{{itemData.system.armorValue}}</div>
{{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}} {{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}}
{{/each}} {{/each}}
</ol> </ol>
@ -137,7 +137,7 @@ documentType='item' type='shield'}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hasQuantity=true
type='equipment'}} type='equipment'}}
{{!-- storage location --}} {{!-- storage location --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="data.storageLocation" <div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.storageLocation"
title="{{localize 'DS4.SortByStorageLocation'}}">{{localize 'DS4.StorageLocation'}}</div> title="{{localize 'DS4.SortByStorageLocation'}}">{{localize 'DS4.StorageLocation'}}</div>
{{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}} {{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}}
{{#each itemsByType.equipment as |itemData id|}} {{#each itemsByType.equipment as |itemData id|}}
@ -145,7 +145,7 @@ documentType='item' type='shield'}}
hasQuantity=true}} hasQuantity=true}}
{{!-- storage location --}} {{!-- storage location --}}
<input class="ds4-embedded-document-list__editable change-item" type="text" <input class="ds4-embedded-document-list__editable change-item" type="text"
value="{{itemData.data.storageLocation}}" data-dtype="String" data-property="data.storageLocation" value="{{itemData.system.storageLocation}}" data-dtype="String" data-property="system.storageLocation"
title="{{localize 'DS4.StorageLocation'}}"> title="{{localize 'DS4.StorageLocation'}}">
{{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}} {{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}}
{{/each}} {{/each}}
@ -160,14 +160,14 @@ documentType='item' type='equipment'}}
<ol class="ds4-embedded-document-list ds4-embedded-document-list--loot item-list"> <ol class="ds4-embedded-document-list ds4-embedded-document-list--loot item-list">
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs hasQuantity=true type='loot'}} {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs hasQuantity=true type='loot'}}
{{!-- storage location --}} {{!-- storage location --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="data.storageLocation" <div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.storageLocation"
title="{{localize 'DS4.SortByStorageLocation'}}">{{localize 'DS4.StorageLocation'}}</div> title="{{localize 'DS4.SortByStorageLocation'}}">{{localize 'DS4.StorageLocation'}}</div>
{{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}} {{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}}
{{#each itemsByType.loot as |itemData id|}} {{#each itemsByType.loot as |itemData id|}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData hasQuantity=true}} {{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData hasQuantity=true}}
{{!-- storage location --}} {{!-- storage location --}}
<input class="ds4-embedded-document-list__editable change-item" type="text" <input class="ds4-embedded-document-list__editable change-item" type="text"
value="{{itemData.data.storageLocation}}" data-dtype="String" data-property="data.storageLocation" value="{{itemData.system.storageLocation}}" data-dtype="String" data-property="system.storageLocation"
title="{{localize 'DS4.StorageLocation'}}"> title="{{localize 'DS4.StorageLocation'}}">
{{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}} {{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}}
{{/each}} {{/each}}

View file

@ -6,24 +6,24 @@ SPDX-License-Identifier: MIT
--}} --}}
<div class="ds4-profile"> <div class="ds4-profile">
{{#each data.data.profile as |profile-data-value profile-data-key|}} {{#each data.system.profile as |profile-data-value profile-data-key|}}
{{#if (and (ne profile-data-key 'biography') (ne profile-data-key 'specialCharacteristics'))}} {{#if (and (ne profile-data-key 'biography') (ne profile-data-key 'specialCharacteristics'))}}
<div class="ds4-profile__entry"> <div class="ds4-profile__entry">
<label class="ds4-profile__entry-label" for="data.profile.{{profile-data-key}}"> <label class="ds4-profile__entry-label" for="system.profile.{{profile-data-key}}">
{{lookup ../config.i18n.characterProfile profile-data-key}} {{lookup ../config.i18n.characterProfile profile-data-key}}
</label> </label>
<input class="ds4-profile__entry-input" type="text" name="data.profile.{{profile-data-key}}" <input class="ds4-profile__entry-input" type="text" name="system.profile.{{profile-data-key}}"
value="{{profile-data-value}}" value="{{profile-data-value}}"
data-dtype="{{lookup ../config.i18n.characterProfileDTypes profile-data-key}}" /> data-dtype="{{lookup ../config.i18n.characterProfileDTypes profile-data-key}}" />
</div> </div>
{{/if}} {{/if}}
{{/each}} {{/each}}
<div class="ds4-profile__entry"> <div class="ds4-profile__entry">
<label class="ds4-profile__entry-label" for="data.profile.specialCharacteristics"> <label class="ds4-profile__entry-label" for="system.profile.specialCharacteristics">
{{lookup config.i18n.characterProfile 'specialCharacteristics'}} {{lookup config.i18n.characterProfile 'specialCharacteristics'}}
</label> </label>
<textarea class="ds4-profile__entry-input ds4-profile__entry-input--multiline" <textarea class="ds4-profile__entry-input ds4-profile__entry-input--multiline"
name="data.profile.specialCharacteristics" data-dtype="String" name="system.profile.specialCharacteristics" data-dtype="String"
rows="4">{{data.data.profile.specialCharacteristics}}</textarea> rows="4">{{data.system.profile.specialCharacteristics}}</textarea>
</div> </div>
</div> </div>

View file

@ -12,13 +12,13 @@ SPDX-License-Identifier: MIT
<ol class="ds4-embedded-document-list ds4-embedded-document-list--talent item-list"> <ol class="ds4-embedded-document-list ds4-embedded-document-list--talent item-list">
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs type='talent'}} {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs type='talent'}}
{{!-- rank --}} {{!-- rank --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="data.rank.total" <div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.rank.total"
title="{{localize 'DS4.SortByTalentRank'}}">{{localize 'DS4.TalentRank'}}</div> title="{{localize 'DS4.SortByTalentRank'}}">{{localize 'DS4.TalentRank'}}</div>
{{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}} {{/systems/ds4/templates/sheets/actor/components/item-list-header.hbs}}
{{#each itemsByType.talent as |itemData id|}} {{#each itemsByType.talent as |itemData id|}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData}} {{#> systems/ds4/templates/sheets/actor/components/item-list-entry.hbs itemData=itemData}}
{{!-- rank --}} {{!-- rank --}}
<div>{{toRomanNumerals itemData.data.rank.total}}</div> <div>{{toRomanNumerals itemData.system.rank.total}}</div>
{{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}} {{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}}
{{/each}} {{/each}}
</ol> </ol>

View file

@ -50,12 +50,12 @@ titleKey=titleKey}}
{{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hideDescription=true {{#> systems/ds4/templates/sheets/actor/components/item-list-header.hbs isEquipable=true hideDescription=true
type='spell'}} type='spell'}}
{{!-- spell type --}} {{!-- spell type --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="data.spellType" <div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.spellType"
title="{{localize 'DS4.SortBySpellType'}}">{{localize 'DS4.SpellTypeAbbr'}}</div> title="{{localize 'DS4.SortBySpellType'}}">{{localize 'DS4.SpellTypeAbbr'}}</div>
{{!-- spell modifier --}} {{!-- spell modifier --}}
<div class="ds4-embedded-document-list__clickable sort-items" data-data-path="data.spellModifier.complex" <div class="ds4-embedded-document-list__clickable sort-items" data-data-path="system.spellModifier.complex"
data-data-path2="data.spellModifier.numerical" title="{{localize 'DS4.SortBySpellModifier'}}">{{localize data-data-path2="system.spellModifier.numerical" title="{{localize 'DS4.SortBySpellModifier'}}">{{localize
'DS4.SpellModifierAbbr'}}</div> 'DS4.SpellModifierAbbr'}}</div>
{{!-- max. distance --}} {{!-- max. distance --}}
@ -73,23 +73,23 @@ titleKey=titleKey}}
hideDescription=true}} hideDescription=true}}
{{!-- spell type --}} {{!-- spell type --}}
<img class="ds4-embedded-document-list__image" <img class="ds4-embedded-document-list__image"
src="{{lookup @root/config.icons.spellTypes itemData.data.spellType}}" src="{{lookup @root/config.icons.spellTypes itemData.system.spellType}}"
title="{{lookup @root/config.i18n.spellTypes itemData.data.spellType}}" /> title="{{lookup @root/config.i18n.spellTypes itemData.system.spellType}}" />
{{!-- spell modifier --}} {{!-- spell modifier --}}
<div title="{{localize 'DS4.SpellModifier'}}">{{#if (eq itemData.data.spellModifier.complex <div title="{{localize 'DS4.SpellModifier'}}">{{#if (eq itemData.system.spellModifier.complex
'')}}{{itemData.data.spellModifier.numerical}}{{else}}{{itemData.data.spellModifier.complex}}{{/if}}</div> '')}}{{itemData.system.spellModifier.numerical}}{{else}}{{itemData.system.spellModifier.complex}}{{/if}}</div>
{{!-- max. distance --}} {{!-- max. distance --}}
{{> distanceUnit titleKey='DS4.SpellDistance' unitDatum=itemData.data.maxDistance {{> distanceUnit titleKey='DS4.SpellDistance' unitDatum=itemData.system.maxDistance
config=@root/config}} config=@root/config}}
{{!-- duration --}} {{!-- duration --}}
{{> temporalUnit titleKey='DS4.SpellDuration' unitDatum=itemData.data.duration config=@root/config}} {{> temporalUnit titleKey='DS4.SpellDuration' unitDatum=itemData.system.duration config=@root/config}}
{{!-- cooldown duration --}} {{!-- cooldown duration --}}
<div title="{{localize 'DS4.CooldownDuration'}}">{{lookup @root/config.i18n.cooldownDurations <div title="{{localize 'DS4.CooldownDuration'}}">{{lookup @root/config.i18n.cooldownDurations
itemData.data.cooldownDuration}}</div> itemData.system.cooldownDuration}}</div>
{{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}} {{/systems/ds4/templates/sheets/actor/components/item-list-entry.hbs}}
{{/each}} {{/each}}

View file

@ -7,10 +7,10 @@ SPDX-License-Identifier: MIT
<div class="ds4-item-properties ds4-item-properties--armor"> <div class="ds4-item-properties ds4-item-properties--armor">
<h4 class="ds4-item-properties__title">{{localize 'DS4.ItemPropertiesArmor'}}</h4> <h4 class="ds4-item-properties__title">{{localize 'DS4.ItemPropertiesArmor'}}</h4>
<div class="form-group"> <div class="form-group">
<label for="data.armorType-{{data._id}}">{{localize "DS4.ArmorType"}}</label> <label for="system.armorType-{{data._id}}">{{localize "DS4.ArmorType"}}</label>
<div class="form-fields"> <div class="form-fields">
<select id="data.armorType-{{data._id}}" name="data.armorType" data-dtype="String"> <select id="system.armorType-{{data._id}}" name="system.armorType" data-dtype="String">
{{#select data.data.armorType}} {{#select data.system.armorType}}
{{#each config.i18n.armorTypes as |value key|}} {{#each config.i18n.armorTypes as |value key|}}
<option value="{{key}}">{{value}}</option> <option value="{{key}}">{{value}}</option>
{{/each}} {{/each}}
@ -19,10 +19,10 @@ SPDX-License-Identifier: MIT
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="data.armorMaterialType-{{data._id}}">{{localize "DS4.ArmorMaterialType"}}</label> <label for="system.armorMaterialType-{{data._id}}">{{localize "DS4.ArmorMaterialType"}}</label>
<div class="form-fields"> <div class="form-fields">
<select id="data.armorMaterialType-{{data._id}}" name="data.armorMaterialType" data-dtype="String"> <select id="system.armorMaterialType-{{data._id}}" name="system.armorMaterialType" data-dtype="String">
{{#select data.data.armorMaterialType}} {{#select data.system.armorMaterialType}}
{{#each config.i18n.armorMaterialTypes as |value key|}} {{#each config.i18n.armorMaterialTypes as |value key|}}
<option value="{{key}}">{{value}}</option> <option value="{{key}}">{{value}}</option>
{{/each}} {{/each}}

View file

@ -7,8 +7,8 @@ SPDX-License-Identifier: MIT
<div class="ds4-item-properties ds4-item-properties--equipable"> <div class="ds4-item-properties ds4-item-properties--equipable">
<h4 class="ds4-item-properties__title">{{localize 'DS4.ItemPropertiesEquipable'}}</h4> <h4 class="ds4-item-properties__title">{{localize 'DS4.ItemPropertiesEquipable'}}</h4>
<div class="form-group"> <div class="form-group">
<label for="data.equipped-{{data._id}}">{{localize "DS4.ItemEquipped"}}</label> <label for="system.equipped-{{data._id}}">{{localize "DS4.ItemEquipped"}}</label>
<input id="data.equipped-{{data._id}}" data-dtype="Boolean" type="checkbox" name="data.equipped" {{checked <input id="system.equipped-{{data._id}}" data-dtype="Boolean" type="checkbox" name="system.equipped" {{checked
data.data.equipped}} /> data.system.equipped}} />
</div> </div>
</div> </div>

View file

@ -7,15 +7,15 @@ SPDX-License-Identifier: MIT
<div class="ds4-item-properties ds4-item-properties--physical"> <div class="ds4-item-properties ds4-item-properties--physical">
<h4 class="ds4-item-properties__title">{{localize 'DS4.ItemPropertiesPhysical'}}</h4> <h4 class="ds4-item-properties__title">{{localize 'DS4.ItemPropertiesPhysical'}}</h4>
<div class="form-group"> <div class="form-group">
<label for="data.price-{{data._id}}">{{localize "DS4.PriceGold"}}</label> <label for="system.price-{{data._id}}">{{localize "DS4.PriceGold"}}</label>
<input id="data.price-{{data._id}}" data-dtype="Number" type="number" min="0" max="99999" step="0.01" <input id="system.price-{{data._id}}" data-dtype="Number" type="number" min="0" max="99999" step="0.01"
placeholder="0" name="data.price" value="{{data.data.price}}" /> placeholder="0" name="system.price" value="{{data.system.price}}" />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="data.availability-{{data._id}}">{{localize "DS4.ItemAvailability"}}</label> <label for="system.availability-{{data._id}}">{{localize "DS4.ItemAvailability"}}</label>
<div class="form-fields"> <div class="form-fields">
<select id="data.availability-{{data._id}}" name="data.availability" data-dtype="String"> <select id="system.availability-{{data._id}}" name="system.availability" data-dtype="String">
{{#select data.data.availability}} {{#select data.system.availability}}
{{#each config.i18n.itemAvailabilities as |value key|}} {{#each config.i18n.itemAvailabilities as |value key|}}
<option value="{{key}}">{{value}}</option> <option value="{{key}}">{{value}}</option>
{{/each}} {{/each}}
@ -25,14 +25,14 @@ SPDX-License-Identifier: MIT
</div> </div>
{{#if isOwned}} {{#if isOwned}}
<div class="form-group"> <div class="form-group">
<label for="data.quantity-{{data._id}}">{{localize "DS4.Quantity"}}</label> <label for="system.quantity-{{data._id}}">{{localize "DS4.Quantity"}}</label>
<input id="data.quantity-{{data._id}}" data-dtype="Number" type="number" name="data.quantity" placeholder="0" <input id="system.quantity-{{data._id}}" data-dtype="Number" type="number" name="system.quantity" placeholder="0"
value="{{data.data.quantity}}" /> value="{{data.system.quantity}}" />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="data.storageLocation-{{data._id}}">{{localize "DS4.StorageLocation"}}</label> <label for="system.storageLocation-{{data._id}}">{{localize "DS4.StorageLocation"}}</label>
<input id="data.storageLocation-{{data._id}}" data-dtype="String" type="text" name="data.storageLocation" <input id="system.storageLocation-{{data._id}}" data-dtype="String" type="text" name="system.storageLocation"
value="{{data.data.storageLocation}}" /> value="{{data.system.storageLocation}}" />
</div> </div>
{{/if}} {{/if}}
</div> </div>

View file

@ -7,8 +7,8 @@ SPDX-License-Identifier: MIT
<div class="ds4-item-properties ds4-item-properties--protective"> <div class="ds4-item-properties ds4-item-properties--protective">
<h4 class="ds4-item-properties__title">{{localize 'DS4.ItemPropertiesProtective'}}</h4> <h4 class="ds4-item-properties__title">{{localize 'DS4.ItemPropertiesProtective'}}</h4>
<div class="form-group"> <div class="form-group">
<label for="data.armorValue-{{data._id}}">{{localize "DS4.ArmorValue"}}</label> <label for="system.armorValue-{{data._id}}">{{localize "DS4.ArmorValue"}}</label>
<input id="data.armorValue-{{data._id}}" data-dtype="Number" type="number" min="0" step="1" placeholder="0" <input id="system.armorValue-{{data._id}}" data-dtype="Number" type="number" min="0" step="1" placeholder="0"
name="data.armorValue" value="{{data.data.armorValue}}" /> name="system.armorValue" value="{{data.system.armorValue}}" />
</div> </div>
</div> </div>

View file

@ -7,9 +7,9 @@ SPDX-License-Identifier: MIT
<div class="ds4-item-properties ds4-item-properties--special-creature-ability"> <div class="ds4-item-properties ds4-item-properties--special-creature-ability">
<h4 class="ds4-item-properties__title">{{localize 'DS4.ItemPropertiesSpecialCreatureAbility'}}</h4> <h4 class="ds4-item-properties__title">{{localize 'DS4.ItemPropertiesSpecialCreatureAbility'}}</h4>
<div class="form-group"> <div class="form-group">
<label for="data.experiencePoints-{{data._id}}">{{localize <label for="system.experiencePoints-{{data._id}}">{{localize
"DS4.SpecialCreatureAbilityExperiencePoints"}}</label> "DS4.SpecialCreatureAbilityExperiencePoints"}}</label>
<input id="data.experiencePoints-{{data._id}}" data-dtype="Number" type="number" min="0" step="1" <input id="system.experiencePoints-{{data._id}}" data-dtype="Number" type="number" min="0" step="1"
placeholder="0" name="data.experiencePoints" value="{{data.data.experiencePoints}}" /> placeholder="0" name="system.experiencePoints" value="{{data.system.experiencePoints}}" />
</div> </div>
</div> </div>

View file

@ -7,29 +7,29 @@ SPDX-License-Identifier: MIT
<div class="ds4-item-properties ds4-item-properties--spell"> <div class="ds4-item-properties ds4-item-properties--spell">
<h4 class="ds4-item-properties__title">{{localize 'DS4.ItemPropertiesSpell'}}</h4> <h4 class="ds4-item-properties__title">{{localize 'DS4.ItemPropertiesSpell'}}</h4>
<div class="form-group"> <div class="form-group">
<label for="data.spellModifier.numerical-{{data._id}}" <label for="system.spellModifier.numerical-{{data._id}}"
title="{{localize 'DS4.SpellModifierNumericalDescription'}}">{{localize title="{{localize 'DS4.SpellModifierNumericalDescription'}}">{{localize
"DS4.SpellModifierNumerical"}}</label> "DS4.SpellModifierNumerical"}}</label>
<div class="form-fields"> <div class="form-fields">
<input id="data.spellModifier.numerical-{{data._id}}" data-dtype="Number" type="number" <input id="system.spellModifier.numerical-{{data._id}}" data-dtype="Number" type="number"
name="data.spellModifier.numerical" placeholder="0" value="{{data.data.spellModifier.numerical}}" /> name="system.spellModifier.numerical" placeholder="0" value="{{data.system.spellModifier.numerical}}" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="data.spellModifier.complex-{{data._id}}" <label for="system.spellModifier.complex-{{data._id}}"
title="{{localize 'DS4.SpellModifierComplexDescription'}}">{{localize title="{{localize 'DS4.SpellModifierComplexDescription'}}">{{localize
"DS4.SpellModifierComplex"}}</label> "DS4.SpellModifierComplex"}}</label>
<div class="form-fields"> <div class="form-fields">
<input id="data.spellModifier.complex-{{data._id}}" data-dtype="String" type="text" <input id="system.spellModifier.complex-{{data._id}}" data-dtype="String" type="text"
name="data.spellModifier.complex" value="{{data.data.spellModifier.complex}}" /> name="system.spellModifier.complex" value="{{data.system.spellModifier.complex}}" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="data.spellType-{{data._id}}" title="{{localize 'DS4.SpellTypeDescription'}}">{{localize <label for="system.spellType-{{data._id}}" title="{{localize 'DS4.SpellTypeDescription'}}">{{localize
"DS4.SpellType"}}</label> "DS4.SpellType"}}</label>
<div class="form-fields"> <div class="form-fields">
<select id="data.spellType-{{data._id}}" name="data.spellType" data-dtype="String"> <select id="system.spellType-{{data._id}}" name="system.spellType" data-dtype="String">
{{#select data.data.spellType}} {{#select data.system.spellType}}
{{#each config.i18n.spellTypes as |value key|}} {{#each config.i18n.spellTypes as |value key|}}
<option value="{{key}}">{{value}}</option> <option value="{{key}}">{{value}}</option>
{{/each}} {{/each}}
@ -40,10 +40,10 @@ SPDX-License-Identifier: MIT
<div class="form-group slim"> <div class="form-group slim">
<label title="{{localize 'DS4.SpellDistanceDescription'}}">{{localize "DS4.SpellDistance"}}</label> <label title="{{localize 'DS4.SpellDistanceDescription'}}">{{localize "DS4.SpellDistance"}}</label>
<div class="form-fields"> <div class="form-fields">
<input data-dtype="String" type="text" name="data.maxDistance.value" <input data-dtype="String" type="text" name="system.maxDistance.value"
value="{{data.data.maxDistance.value}}" /> value="{{data.system.maxDistance.value}}" />
<select name="data.maxDistance.unit" data-dtype="String"> <select name="system.maxDistance.unit" data-dtype="String">
{{#select data.data.maxDistance.unit}} {{#select data.system.maxDistance.unit}}
{{#each config.i18n.distanceUnits as |value key|}} {{#each config.i18n.distanceUnits as |value key|}}
<option value="{{key}}">{{value}}</option> <option value="{{key}}">{{value}}</option>
{{/each}} {{/each}}
@ -54,10 +54,10 @@ SPDX-License-Identifier: MIT
<div class="form-group slim"> <div class="form-group slim">
<label title="{{localize 'DS4.SpellEffectRadiusDescription'}}">{{localize "DS4.SpellEffectRadius"}}</label> <label title="{{localize 'DS4.SpellEffectRadiusDescription'}}">{{localize "DS4.SpellEffectRadius"}}</label>
<div class="form-fields"> <div class="form-fields">
<input data-dtype="String" type="text" name="data.effectRadius.value" <input data-dtype="String" type="text" name="system.effectRadius.value"
value="{{data.data.effectRadius.value}}" /> value="{{data.system.effectRadius.value}}" />
<select name="data.effectRadius.unit" data-dtype="String"> <select name="system.effectRadius.unit" data-dtype="String">
{{#select data.data.effectRadius.unit}} {{#select data.system.effectRadius.unit}}
{{#each config.i18n.distanceUnits as |value key|}} {{#each config.i18n.distanceUnits as |value key|}}
<option value="{{key}}">{{value}}</option> <option value="{{key}}">{{value}}</option>
{{/each}} {{/each}}
@ -68,9 +68,9 @@ SPDX-License-Identifier: MIT
<div class="form-group slim"> <div class="form-group slim">
<label title="{{localize 'DS4.SpellDurationDescription'}}">{{localize "DS4.SpellDuration"}}</label> <label title="{{localize 'DS4.SpellDurationDescription'}}">{{localize "DS4.SpellDuration"}}</label>
<div class="form-fields"> <div class="form-fields">
<input data-dtype="String" type="text" name="data.duration.value" value="{{data.data.duration.value}}" /> <input data-dtype="String" type="text" name="system.duration.value" value="{{data.system.duration.value}}" />
<select name="data.duration.unit" data-dtype="String"> <select name="system.duration.unit" data-dtype="String">
{{#select data.data.duration.unit}} {{#select data.system.duration.unit}}
{{#each config.i18n.temporalUnits as |value key|}} {{#each config.i18n.temporalUnits as |value key|}}
<option value="{{key}}">{{value}}</option> <option value="{{key}}">{{value}}</option>
{{/each}} {{/each}}
@ -79,11 +79,11 @@ SPDX-License-Identifier: MIT
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="data.cooldownDuration-{{data._id}}" <label for="system.cooldownDuration-{{data._id}}"
title="{{localize 'DS4.CooldownDurationDescription'}}">{{localize "DS4.CooldownDuration"}}</label> title="{{localize 'DS4.CooldownDurationDescription'}}">{{localize "DS4.CooldownDuration"}}</label>
<div class="form-fields"> <div class="form-fields">
<select id="data.cooldownDuration-{{data._id}}" name="data.cooldownDuration" data-dtype="String"> <select id="system.cooldownDuration-{{data._id}}" name="system.cooldownDuration" data-dtype="String">
{{#select data.data.cooldownDuration}} {{#select data.system.cooldownDuration}}
{{#each config.i18n.cooldownDurations as |value key|}} {{#each config.i18n.cooldownDurations as |value key|}}
<option value="{{key}}">{{value}}</option> <option value="{{key}}">{{value}}</option>
{{/each}} {{/each}}
@ -97,42 +97,42 @@ SPDX-License-Identifier: MIT
<div class="ds4-checkbox-grid"> <div class="ds4-checkbox-grid">
{{#each config.i18n.spellGroups as |value key|}} {{#each config.i18n.spellGroups as |value key|}}
<div class="ds4-checkbox-grid__item"> <div class="ds4-checkbox-grid__item">
<input class="ds4-checkbox-grid__checkbox" id="data.spellGroups.{{key}}-{{../data._id}}" <input class="ds4-checkbox-grid__checkbox" id="system.spellGroups.{{key}}-{{../data._id}}"
name="data.spellGroups.{{key}}" data-dtype="Boolean" type="checkbox" {{checked (lookup name="system.spellGroups.{{key}}" data-dtype="Boolean" type="checkbox" {{checked (lookup
../data.data.spellGroups key)}} /> ../data.system.spellGroups key)}} />
<label for="data.spellGroups.{{key}}-{{../data._id}}">{{value}}</label> <label for="system.spellGroups.{{key}}-{{../data._id}}">{{value}}</label>
</div> </div>
{{/each}} {{/each}}
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="data.allowsDefense-{{data._id}}" title="{{localize 'DS4.SpellAllowsDefenseDescription'}}">{{localize <label for="system.allowsDefense-{{data._id}}" title="{{localize 'DS4.SpellAllowsDefenseDescription'}}">{{localize
"DS4.SpellAllowsDefense"}}</label> "DS4.SpellAllowsDefense"}}</label>
<div class="form-fields"> <div class="form-fields">
<input id="data.allowsDefense-{{data._id}}" data-dtype="Boolean" type="checkbox" name="data.allowsDefense" <input id="system.allowsDefense-{{data._id}}" data-dtype="Boolean" type="checkbox" name="system.allowsDefense"
{{checked data.data.allowsDefense}} /> {{checked data.system.allowsDefense}} />
</div> </div>
</div> </div>
<div class="form-group slim"> <div class="form-group slim">
<label title="{{localize 'DS4.SpellMinimumLevelDescription'}}">{{localize "DS4.SpellMinimumLevel"}}</label> <label title="{{localize 'DS4.SpellMinimumLevelDescription'}}">{{localize "DS4.SpellMinimumLevel"}}</label>
<div class="form-fields"> <div class="form-fields">
<label for="data.minimumLevels.healer-{{data._id}}">{{localize "DS4.SpellCasterClassHealer"}}</label> <label for="system.minimumLevels.healer-{{data._id}}">{{localize "DS4.SpellCasterClassHealer"}}</label>
<input id="data.minimumLevels.healer-{{data._id}}" data-dtype="Number" type="number" min="0" step="1" <input id="system.minimumLevels.healer-{{data._id}}" data-dtype="Number" type="number" min="0" step="1"
name="data.minimumLevels.healer" placeholder="" value="{{data.data.minimumLevels.healer}}" /> name="system.minimumLevels.healer" placeholder="" value="{{data.system.minimumLevels.healer}}" />
<label for="data.minimumLevels.wizard-{{data._id}}">{{localize "DS4.SpellCasterClassWizard"}}</label> <label for="system.minimumLevels.wizard-{{data._id}}">{{localize "DS4.SpellCasterClassWizard"}}</label>
<input id="data.minimumLevels.wizard-{{data._id}}" data-dtype="Number" type="number" min="0" step="1" <input id="system.minimumLevels.wizard-{{data._id}}" data-dtype="Number" type="number" min="0" step="1"
name="data.minimumLevels.wizard" placeholder="" value="{{data.data.minimumLevels.wizard}}" /> name="system.minimumLevels.wizard" placeholder="" value="{{data.system.minimumLevels.wizard}}" />
<label for="data.minimumLevels.sorcerer-{{data._id}}">{{localize <label for="system.minimumLevels.sorcerer-{{data._id}}">{{localize
"DS4.SpellCasterClassSorcerer"}}</label> "DS4.SpellCasterClassSorcerer"}}</label>
<input id="data.minimumLevels.sorcerer-{{data._id}}" data-dtype="Number" type="number" min="0" step="1" <input id="system.minimumLevels.sorcerer-{{data._id}}" data-dtype="Number" type="number" min="0" step="1"
name="data.minimumLevels.sorcerer" placeholder="" value="{{data.data.minimumLevels.sorcerer}}" /> name="system.minimumLevels.sorcerer" placeholder="" value="{{data.system.minimumLevels.sorcerer}}" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="data.price-{{data._id}}" title="{{localize 'DS4.SpellPriceDescription'}}">{{localize <label for="system.price-{{data._id}}" title="{{localize 'DS4.SpellPriceDescription'}}">{{localize
"DS4.SpellPrice"}}</label> "DS4.SpellPrice"}}</label>
<div class="form-fields"> <div class="form-fields">
<span id="data.price-{{data._id}}">{{data.data.price}}</span> <span id="system.price-{{data._id}}">{{data.system.price}}</span>
</div> </div>
</div> </div>
</div> </div>

View file

@ -9,18 +9,18 @@ SPDX-License-Identifier: MIT
<div class="form-group slim"> <div class="form-group slim">
<label>{{localize "DS4.TalentRank"}}</label> <label>{{localize "DS4.TalentRank"}}</label>
<div class="form-fields"> <div class="form-fields">
<label for="data.rank.base-{{data._id}}">{{localize "DS4.TalentRankBase"}}</label> <label for="system.rank.base-{{data._id}}">{{localize "DS4.TalentRankBase"}}</label>
<input id="data.rank.base-{{data._id}}" data-dtype="Number" type="number" min="0" <input id="system.rank.base-{{data._id}}" data-dtype="Number" type="number" min="0"
max="{{data.data.rank.max}}" step="1" name="data.rank.base" value="{{data.data.rank.base}}" /> max="{{data.system.rank.max}}" step="1" name="system.rank.base" value="{{data.system.rank.base}}" />
<label for="data.rank.max-{{data._id}}">{{localize "DS4.TalentRankMax"}}</label> <label for="system.rank.max-{{data._id}}">{{localize "DS4.TalentRankMax"}}</label>
<input id="data.rank.max-{{data._id}}" data-dtype="Number" type="number" min="0" step="1" <input id="system.rank.max-{{data._id}}" data-dtype="Number" type="number" min="0" step="1"
name="data.rank.max" value="{{data.data.rank.max}}" /> name="system.rank.max" value="{{data.system.rank.max}}" />
<br /> <br />
<label for="data.rank.mod-{{data._id}}">{{localize "DS4.TalentRankMod"}}</label> <label for="system.rank.mod-{{data._id}}">{{localize "DS4.TalentRankMod"}}</label>
<input id="data.rank.mod-{{data._id}}" data-dtype="Number" type="number" min="0" step="1" <input id="system.rank.mod-{{data._id}}" data-dtype="Number" type="number" min="0" step="1"
name="data.rank.mod" value="{{data.data.rank.mod}}" /> name="system.rank.mod" value="{{data.system.rank.mod}}" />
<label for="data.rank.total-{{data._id}}">{{localize "DS4.TalentRankTotal"}}</label> <label for="system.rank.total-{{data._id}}">{{localize "DS4.TalentRankTotal"}}</label>
<span id="data.rank.total-{{data._id}}">{{data.data.rank.total}}</span> <span id="system.rank.total-{{data._id}}">{{data.system.rank.total}}</span>
</div> </div>
</div> </div>
</div> </div>

View file

@ -7,10 +7,10 @@ SPDX-License-Identifier: MIT
<div class="ds4-item-properties ds4-item-properties--weapon"> <div class="ds4-item-properties ds4-item-properties--weapon">
<h4 class="ds4-item-properties__title">{{localize 'DS4.ItemPropertiesWeapon'}}</h4> <h4 class="ds4-item-properties__title">{{localize 'DS4.ItemPropertiesWeapon'}}</h4>
<div class="form-group"> <div class="form-group">
<label for="data.attackType-{{data._id}}">{{localize "DS4.AttackType"}}</label> <label for="system.attackType-{{data._id}}">{{localize "DS4.AttackType"}}</label>
<div class="form-fields"> <div class="form-fields">
<select id="data.attackType-{{data._id}}" name="data.attackType" data-dtype="String"> <select id="system.attackType-{{data._id}}" name="system.attackType" data-dtype="String">
{{#select data.data.attackType}} {{#select data.system.attackType}}
{{#each config.i18n.attackTypes as |value key|}} {{#each config.i18n.attackTypes as |value key|}}
<option value="{{key}}">{{value}}</option> <option value="{{key}}">{{value}}</option>
{{/each}} {{/each}}
@ -19,13 +19,13 @@ SPDX-License-Identifier: MIT
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="data.weaponBonus-{{data._id}}">{{localize "DS4.WeaponBonus"}}</label> <label for="system.weaponBonus-{{data._id}}">{{localize "DS4.WeaponBonus"}}</label>
<input id="data.weaponBonus-{{data._id}}" data-dtype="Number" type="number" name="data.weaponBonus" <input id="system.weaponBonus-{{data._id}}" data-dtype="Number" type="number" name="system.weaponBonus"
placeholder="0" value="{{data.data.weaponBonus}}" /> placeholder="0" value="{{data.system.weaponBonus}}" />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="data.opponentDefense-{{data._id}}">{{localize "DS4.OpponentDefense"}}</label> <label for="system.opponentDefense-{{data._id}}">{{localize "DS4.OpponentDefense"}}</label>
<input id="data.opponentDefense-{{data._id}}" data-dtype="Number" type="number" name="data.opponentDefense" <input id="system.opponentDefense-{{data._id}}" data-dtype="Number" type="number" name="system.opponentDefense"
placeholder="0" value="{{data.data.opponentDefense}}" /> placeholder="0" value="{{data.system.opponentDefense}}" />
</div> </div>
</div> </div>

View file

@ -5,6 +5,6 @@ SPDX-License-Identifier: MIT
--}} --}}
<div class="ds4-sheet-tab tab description" data-group="primary" data-tab="description"> <div class="ds4-sheet-tab tab description" data-group="primary" data-tab="description">
{{editor content=data.data.description target="data.description" button=true owner=owner {{editor data.system.description target="system.description" button=true owner=owner
editable=editable}} editable=editable engine="prosemirror"}}
</div> </div>

View file

@ -18,6 +18,7 @@ function cleanPackEntry(entry, cleanSourceId = true) {
} }
}); });
if (entry.permission) entry.permission = { default: 0 }; if (entry.permission) entry.permission = { default: 0 };
if (entry._stats?.lastModifiedBy) entry._stats.lastModifiedBy = "DS4BuildSystem00";
const embeddedDocumentCollections = [ const embeddedDocumentCollections = [
"drawings", "drawings",