mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-11 19:25:21 +01:00
[Fix] Itemlink Redux Revengeance (#399)
* Small random fixes * Added use of ItemLinkFields * Multiclass levelup fixes * Fixed our onCreate methods unintentionally being run on all clients * Remade apps handling * Added for all class items and subclass * Restored foreignDocumentUuidField * Improved * PR fxies * Fixed tooltip enrichment * . * Reverted silly change
This commit is contained in:
parent
fcba5041e9
commit
2a4777f1a0
61 changed files with 648 additions and 489 deletions
|
|
@ -3,7 +3,7 @@ import * as applications from './module/applications/_module.mjs';
|
||||||
import * as models from './module/data/_module.mjs';
|
import * as models from './module/data/_module.mjs';
|
||||||
import * as documents from './module/documents/_module.mjs';
|
import * as documents from './module/documents/_module.mjs';
|
||||||
import * as dice from './module/dice/_module.mjs';
|
import * as dice from './module/dice/_module.mjs';
|
||||||
import * as fields from './module/data/fields/_module.mjs'
|
import * as fields from './module/data/fields/_module.mjs';
|
||||||
import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs';
|
import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs';
|
||||||
import { enricherConfig, enricherRenderSetup } from './module/enrichers/_module.mjs';
|
import { enricherConfig, enricherRenderSetup } from './module/enrichers/_module.mjs';
|
||||||
import { getCommandTarget, rollCommandToJSON } from './module/helpers/utils.mjs';
|
import { getCommandTarget, rollCommandToJSON } from './module/helpers/utils.mjs';
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,11 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
||||||
|
|
||||||
_getSetupTabs(tabs) {
|
_getSetupTabs(tabs) {
|
||||||
for (const v of Object.values(tabs)) {
|
for (const v of Object.values(tabs)) {
|
||||||
v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active;
|
v.active = this.tabGroups[v.group]
|
||||||
|
? this.tabGroups[v.group] === v.id
|
||||||
|
: this.tabGroups.primary !== 'equipment'
|
||||||
|
? v.active
|
||||||
|
: false;
|
||||||
v.cssClass = v.active ? 'active' : '';
|
v.cssClass = v.active ? 'active' : '';
|
||||||
|
|
||||||
switch (v.id) {
|
switch (v.id) {
|
||||||
|
|
@ -242,6 +246,16 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
||||||
marker.classList.remove('active');
|
marker.classList.remove('active');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tab === 'equipment') {
|
||||||
|
this.tabGroups.setup = null;
|
||||||
|
this.element.querySelector('section[data-group="setup"].active')?.classList?.remove?.('active');
|
||||||
|
} else {
|
||||||
|
this.tabGroups.setup = 'domainCards';
|
||||||
|
this.element
|
||||||
|
.querySelector('section[data-group="setup"][data-tab="domainCards"]')
|
||||||
|
?.classList?.add?.('active');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,6 +270,11 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _preFirstRender(_context, _options) {
|
||||||
|
this.tabGroups.primary = 'setup';
|
||||||
|
this.tabGroups.setup = 'ancestry';
|
||||||
|
}
|
||||||
|
|
||||||
async _prepareContext(_options) {
|
async _prepareContext(_options) {
|
||||||
const context = await super._prepareContext(_options);
|
const context = await super._prepareContext(_options);
|
||||||
context.tabs = this._getTabs(this.constructor.TABS);
|
context.tabs = this._getTabs(this.constructor.TABS);
|
||||||
|
|
@ -266,7 +285,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
||||||
async _preparePartContext(partId, context) {
|
async _preparePartContext(partId, context) {
|
||||||
switch (partId) {
|
switch (partId) {
|
||||||
case 'footer':
|
case 'footer':
|
||||||
context.isLastTab = this.tabGroups.setup === 'domainCards';
|
context.isLastTab = this.tabGroups.setup === 'domainCards' || this.tabGroups.primary !== 'setup';
|
||||||
switch (this.tabGroups.setup) {
|
switch (this.tabGroups.setup) {
|
||||||
case null:
|
case null:
|
||||||
case 'ancestry':
|
case 'ancestry':
|
||||||
|
|
@ -321,10 +340,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
context.traits.nrTotal = Object.keys(context.traits.values).length;
|
context.traits.nrTotal = Object.keys(context.traits.values).length;
|
||||||
context.traits.nrSelected = Object.values(context.traits.values).reduce(
|
context.traits.nrSelected = this.getNrSelectedTrait();
|
||||||
(acc, trait) => acc + (trait.value !== null ? 1 : 0),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
context.experience = {
|
context.experience = {
|
||||||
values: this.setup.experiences,
|
values: this.setup.experiences,
|
||||||
|
|
@ -378,6 +394,10 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
||||||
choiceA: { suggestions: suggestions.inventory.choiceA, compendium: 'consumables' },
|
choiceA: { suggestions: suggestions.inventory.choiceA, compendium: 'consumables' },
|
||||||
choiceB: { suggestions: suggestions.inventory.choiceB, compendium: 'general-items' }
|
choiceB: { suggestions: suggestions.inventory.choiceB, compendium: 'general-items' }
|
||||||
};
|
};
|
||||||
|
context.noInventoryChoices =
|
||||||
|
suggestions.inventory.take.length === 0 &&
|
||||||
|
suggestions.inventory.choiceA?.length === 0 &&
|
||||||
|
suggestions.inventory.choiceB?.length === 0;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -408,7 +428,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
||||||
case 5:
|
case 5:
|
||||||
return Object.values(this.setup.experiences).every(x => x.name) ? 6 : 5;
|
return Object.values(this.setup.experiences).every(x => x.name) ? 6 : 5;
|
||||||
case 4:
|
case 4:
|
||||||
return Object.values(this.setup.traits).every(x => x.value !== null) ? 5 : 4;
|
return this.getNrSelectedTrait() === 6 ? 5 : 4;
|
||||||
case 3:
|
case 3:
|
||||||
return this.setup.class.uuid && this.setup.subclass.uuid ? 4 : 3;
|
return this.setup.class.uuid && this.setup.subclass.uuid ? 4 : 3;
|
||||||
case 2:
|
case 2:
|
||||||
|
|
@ -418,6 +438,18 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getNrSelectedTrait() {
|
||||||
|
const traitCompareArray = [
|
||||||
|
...game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).traitArray
|
||||||
|
];
|
||||||
|
return Object.values(this.setup.traits).reduce((acc, x) => {
|
||||||
|
const index = traitCompareArray.indexOf(x.value);
|
||||||
|
traitCompareArray.splice(index, 1);
|
||||||
|
acc += index !== -1;
|
||||||
|
return acc;
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
async getEquipmentSuggestions(choiceA, choiceB) {
|
async getEquipmentSuggestions(choiceA, choiceB) {
|
||||||
if (!this.setup.class.uuid) return { inventory: { take: [] } };
|
if (!this.setup.class.uuid) return { inventory: { take: [] } };
|
||||||
|
|
||||||
|
|
@ -429,10 +461,15 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
||||||
? { ...characterGuide.suggestedSecondaryWeapon, uuid: characterGuide.suggestedSecondaryWeapon.uuid }
|
? { ...characterGuide.suggestedSecondaryWeapon, uuid: characterGuide.suggestedSecondaryWeapon.uuid }
|
||||||
: null,
|
: null,
|
||||||
inventory: {
|
inventory: {
|
||||||
take: inventory.take ?? [],
|
take: inventory.take?.filter(x => x) ?? [],
|
||||||
choiceA:
|
choiceA:
|
||||||
inventory.choiceA?.map(x => ({ ...x, uuid: x.uuid, selected: x.uuid === choiceA?.uuid })) ?? [],
|
inventory.choiceA
|
||||||
choiceB: inventory.choiceB?.map(x => ({ ...x, uuid: x.uuid, selected: x.uuid === choiceB?.uuid })) ?? []
|
?.filter(x => x)
|
||||||
|
.map(x => ({ ...x, uuid: x.uuid, selected: x.uuid === choiceA?.uuid })) ?? [],
|
||||||
|
choiceB:
|
||||||
|
inventory.choiceB
|
||||||
|
?.filter(x => x)
|
||||||
|
.map(x => ({ ...x, uuid: x.uuid, selected: x.uuid === choiceB?.uuid })) ?? []
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -506,7 +543,10 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
||||||
name: this.setup.ancestryName ?? this.setup.primaryAncestry.name,
|
name: this.setup.ancestryName ?? this.setup.primaryAncestry.name,
|
||||||
system: {
|
system: {
|
||||||
...this.setup.primaryAncestry.system,
|
...this.setup.primaryAncestry.system,
|
||||||
features: [primaryAncestryFeature.uuid, secondaryAncestryFeature.uuid]
|
features: [
|
||||||
|
{ type: 'primary', item: primaryAncestryFeature.uuid },
|
||||||
|
{ type: 'secondary', item: secondaryAncestryFeature.uuid }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -535,7 +575,10 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
||||||
await this.character.createEmbeddedDocuments('Item', [this.equipment.inventory.choiceA]);
|
await this.character.createEmbeddedDocuments('Item', [this.equipment.inventory.choiceA]);
|
||||||
if (this.equipment.inventory.choiceB.uuid)
|
if (this.equipment.inventory.choiceB.uuid)
|
||||||
await this.character.createEmbeddedDocuments('Item', [this.equipment.inventory.choiceB]);
|
await this.character.createEmbeddedDocuments('Item', [this.equipment.inventory.choiceB]);
|
||||||
await this.character.createEmbeddedDocuments('Item', this.setup.class.system.inventory.take);
|
await this.character.createEmbeddedDocuments(
|
||||||
|
'Item',
|
||||||
|
this.setup.class.system.inventory.take.filter(x => x)
|
||||||
|
);
|
||||||
|
|
||||||
await this.character.update({
|
await this.character.update({
|
||||||
system: {
|
system: {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
|
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
|
||||||
|
|
||||||
export default class ActionSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) {
|
export default class ActionSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
constructor(item, event, options={}) {
|
constructor(item, event, options = {}) {
|
||||||
super(options);
|
super(options);
|
||||||
this.#item = item;
|
this.#item = item;
|
||||||
this.#event = event;
|
this.#event = event;
|
||||||
|
|
@ -24,7 +24,7 @@ export default class ActionSelectionDialog extends HandlebarsApplicationMixin(Ap
|
||||||
|
|
||||||
static PARTS = {
|
static PARTS = {
|
||||||
actions: {
|
actions: {
|
||||||
template: "systems/daggerheart/templates/dialogs/actionSelect.hbs"
|
template: 'systems/daggerheart/templates/dialogs/actionSelect.hbs'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -60,10 +60,10 @@ export default class ActionSelectionDialog extends HandlebarsApplicationMixin(Ap
|
||||||
const actions = this.#item.system.actionsList,
|
const actions = this.#item.system.actionsList,
|
||||||
itemName = this.#item.name;
|
itemName = this.#item.name;
|
||||||
return {
|
return {
|
||||||
...await super._prepareContext(options),
|
...(await super._prepareContext(options)),
|
||||||
actions,
|
actions,
|
||||||
itemName
|
itemName
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #onChooseAction(event, button) {
|
static async #onChooseAction(event, button) {
|
||||||
|
|
@ -80,8 +80,8 @@ export default class ActionSelectionDialog extends HandlebarsApplicationMixin(Ap
|
||||||
static create(item, event, options) {
|
static create(item, event, options) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const dialog = new this(item, event, options);
|
const dialog = new this(item, event, options);
|
||||||
dialog.addEventListener("close", () => resolve(dialog.action), { once: true });
|
dialog.addEventListener('close', () => resolve(dialog.action), { once: true });
|
||||||
dialog.render({ force: true });
|
dialog.render({ force: true });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,10 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (this.config.costs?.length) {
|
if (this.config.costs?.length) {
|
||||||
const updatedCosts = game.system.api.fields.ActionFields.CostField.calcCosts.call(this.action, this.config.costs);
|
const updatedCosts = game.system.api.fields.ActionFields.CostField.calcCosts.call(
|
||||||
|
this.action,
|
||||||
|
this.config.costs
|
||||||
|
);
|
||||||
context.costs = updatedCosts.map(x => ({
|
context.costs = updatedCosts.map(x => ({
|
||||||
...x,
|
...x,
|
||||||
label: x.keyIsID
|
label: x.keyIsID
|
||||||
|
|
@ -80,7 +83,9 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
}
|
}
|
||||||
if (this.config.uses?.max) {
|
if (this.config.uses?.max) {
|
||||||
context.uses = game.system.api.fields.ActionFields.UsesField.calcUses.call(this.action, this.config.uses);
|
context.uses = game.system.api.fields.ActionFields.UsesField.calcUses.call(this.action, this.config.uses);
|
||||||
context.canRoll = context.canRoll && game.system.api.fields.ActionFields.UsesField.hasUses.call(this.action, context.uses);
|
context.canRoll =
|
||||||
|
context.canRoll &&
|
||||||
|
game.system.api.fields.ActionFields.UsesField.hasUses.call(this.action, context.uses);
|
||||||
}
|
}
|
||||||
if (this.roll) {
|
if (this.roll) {
|
||||||
context.roll = this.roll;
|
context.roll = this.roll;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import LevelUpBase from './levelup.mjs';
|
import LevelUpBase from './levelup.mjs';
|
||||||
import { DhLevelup } from '../../data/levelup.mjs';
|
import { DhLevelup } from '../../data/levelup.mjs';
|
||||||
import { domains } from '../../config/domainConfig.mjs';
|
import { domains } from '../../config/domainConfig.mjs';
|
||||||
import { abilities } from '../../config/actorConfig.mjs';
|
import { abilities, subclassFeatureLabels } from '../../config/actorConfig.mjs';
|
||||||
|
|
||||||
export default class DhCharacterLevelUp extends LevelUpBase {
|
export default class DhCharacterLevelUp extends LevelUpBase {
|
||||||
constructor(actor) {
|
constructor(actor) {
|
||||||
|
|
@ -166,6 +166,7 @@ export default class DhCharacterLevelUp extends LevelUpBase {
|
||||||
context.multiclass = {
|
context.multiclass = {
|
||||||
...data,
|
...data,
|
||||||
...(multiclass.toObject?.() ?? multiclass),
|
...(multiclass.toObject?.() ?? multiclass),
|
||||||
|
type: 'multiclass',
|
||||||
uuid: multiclass.uuid,
|
uuid: multiclass.uuid,
|
||||||
domains:
|
domains:
|
||||||
multiclass?.system?.domains.map(key => {
|
multiclass?.system?.domains.map(key => {
|
||||||
|
|
@ -349,8 +350,8 @@ export default class DhCharacterLevelUp extends LevelUpBase {
|
||||||
if (!acc) acc = {};
|
if (!acc) acc = {};
|
||||||
acc[traitKey] = {
|
acc[traitKey] = {
|
||||||
label: game.i18n.localize(abilities[traitKey].label),
|
label: game.i18n.localize(abilities[traitKey].label),
|
||||||
old: this.actor.system.traits[traitKey].max,
|
old: this.actor.system.traits[traitKey].value,
|
||||||
new: this.actor.system.traits[traitKey].max + advancement.trait[traitKey]
|
new: this.actor.system.traits[traitKey].value + advancement.trait[traitKey]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return acc;
|
return acc;
|
||||||
|
|
|
||||||
|
|
@ -452,6 +452,12 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const secondaryData = Object.keys(
|
||||||
|
foundry.utils.getProperty(this.levelup, `${target.dataset.path}.secondaryData`)
|
||||||
|
).reduce((acc, key) => {
|
||||||
|
acc[`-=${key}`] = null;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
await this.levelup.updateSource({
|
await this.levelup.updateSource({
|
||||||
multiclass: {
|
multiclass: {
|
||||||
class: item.uuid,
|
class: item.uuid,
|
||||||
|
|
@ -464,7 +470,8 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
|
||||||
amount: target.dataset.amount ? Number(target.dataset.amount) : null,
|
amount: target.dataset.amount ? Number(target.dataset.amount) : null,
|
||||||
value: target.dataset.value,
|
value: target.dataset.value,
|
||||||
type: target.dataset.type,
|
type: target.dataset.type,
|
||||||
data: item.uuid
|
data: item.uuid,
|
||||||
|
secondaryData: secondaryData
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.render();
|
this.render();
|
||||||
|
|
@ -538,10 +545,21 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
|
||||||
static async selectDomain(_, button) {
|
static async selectDomain(_, button) {
|
||||||
const option = foundry.utils.getProperty(this.levelup, button.dataset.path);
|
const option = foundry.utils.getProperty(this.levelup, button.dataset.path);
|
||||||
const domain = option.secondaryData.domain ? null : button.dataset.domain;
|
const domain = option.secondaryData.domain ? null : button.dataset.domain;
|
||||||
|
const update = { [`${button.dataset.path}.secondaryData.domain`]: domain };
|
||||||
|
|
||||||
await this.levelup.updateSource({
|
const domainCards = this.levelup.levels[this.levelup.currentLevel].achievements.domainCards;
|
||||||
[`${button.dataset.path}.secondaryData.domain`]: domain
|
const illegalDomainCards = option.secondaryData.domain
|
||||||
|
? Object.keys(domainCards)
|
||||||
|
.map(key => ({ ...domainCards[key], key }))
|
||||||
|
.filter(
|
||||||
|
x => x.uuid && foundry.utils.fromUuidSync(x.uuid).system.domain === option.secondaryData.domain
|
||||||
|
)
|
||||||
|
: [];
|
||||||
|
illegalDomainCards.forEach(card => {
|
||||||
|
update[`levels.${this.levelup.currentLevel}.achievements.domainCards.${card.key}.uuid`] = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await this.levelup.updateSource(update);
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,13 @@ export default function DHApplicationMixin(Base) {
|
||||||
tagifyConfigs: []
|
tagifyConfigs: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Related documents that should cause a rerender of this application when updated.
|
||||||
|
*/
|
||||||
|
get relatedDocs() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**@inheritdoc */
|
/**@inheritdoc */
|
||||||
|
|
@ -117,9 +124,17 @@ export default function DHApplicationMixin(Base) {
|
||||||
/**@inheritdoc */
|
/**@inheritdoc */
|
||||||
async _onFirstRender(context, options) {
|
async _onFirstRender(context, options) {
|
||||||
await super._onFirstRender(context, options);
|
await super._onFirstRender(context, options);
|
||||||
|
this.relatedDocs.filter(doc => doc).map(doc => (doc.apps[this.id] = this));
|
||||||
|
|
||||||
if (!!this.options.contextMenus.length) this._createContextMenus();
|
if (!!this.options.contextMenus.length) this._createContextMenus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
_onClose(options) {
|
||||||
|
super._onClose(options);
|
||||||
|
this.relatedDocs.filter(doc => doc).map(doc => delete doc.apps[this.id]);
|
||||||
|
}
|
||||||
|
|
||||||
/**@inheritdoc */
|
/**@inheritdoc */
|
||||||
async _onRender(context, options) {
|
async _onRender(context, options) {
|
||||||
await super._onRender(context, options);
|
await super._onRender(context, options);
|
||||||
|
|
@ -285,7 +300,7 @@ export default function DHApplicationMixin(Base) {
|
||||||
icon: 'fa-solid fa-pen-to-square',
|
icon: 'fa-solid fa-pen-to-square',
|
||||||
condition: target => {
|
condition: target => {
|
||||||
const doc = getDocFromElement(target);
|
const doc = getDocFromElement(target);
|
||||||
return !doc.hasOwnProperty('systemPath') || doc.inCollection
|
return !doc.hasOwnProperty('systemPath') || doc.inCollection;
|
||||||
},
|
},
|
||||||
callback: target => getDocFromElement(target).sheet.render({ force: true })
|
callback: target => getDocFromElement(target).sheet.render({ force: true })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -150,13 +150,15 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
||||||
static async #addFeature(_, target) {
|
static async #addFeature(_, target) {
|
||||||
const { type } = target.dataset;
|
const { type } = target.dataset;
|
||||||
const cls = foundry.documents.Item.implementation;
|
const cls = foundry.documents.Item.implementation;
|
||||||
const feature = await cls.create({
|
const item = await cls.create({
|
||||||
'type': 'feature',
|
type: 'feature',
|
||||||
'name': cls.defaultName({ type: 'feature' }),
|
name: cls.defaultName({ type: 'feature' })
|
||||||
'system.subType': CONFIG.DH.ITEM.featureSubTypes[type]
|
|
||||||
});
|
});
|
||||||
await this.document.update({
|
await this.document.update({
|
||||||
'system.features': [...this.document.system.features, feature].map(f => f.uuid)
|
'system.features': [...this.document.system.features, { type, item }].map(x => ({
|
||||||
|
...x,
|
||||||
|
item: x.item?.uuid
|
||||||
|
}))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,12 +166,14 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
||||||
* Remove a feature from the item.
|
* Remove a feature from the item.
|
||||||
* @type {ApplicationClickAction}
|
* @type {ApplicationClickAction}
|
||||||
*/
|
*/
|
||||||
static async #deleteFeature(_, target) {
|
static async #deleteFeature(_, element) {
|
||||||
|
const target = element.closest('[data-item-uuid]');
|
||||||
const feature = getDocFromElement(target);
|
const feature = getDocFromElement(target);
|
||||||
if (!feature) return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureIsMissing'));
|
if (!feature) return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureIsMissing'));
|
||||||
await feature.update({ 'system.subType': null });
|
|
||||||
await this.document.update({
|
await this.document.update({
|
||||||
'system.features': this.document.system.features.map(x => x.uuid).filter(uuid => uuid !== feature.uuid)
|
'system.features': this.document.system.features
|
||||||
|
.filter(x => target.dataset.type !== x.type || x.item.uuid !== feature.uuid)
|
||||||
|
.map(x => ({ ...x, item: x.item.uuid }))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -242,10 +246,15 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
||||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
|
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
|
||||||
if (data.fromInternal) return;
|
if (data.fromInternal) return;
|
||||||
|
|
||||||
|
const target = event.target.closest('fieldset.drop-section');
|
||||||
const item = await fromUuid(data.uuid);
|
const item = await fromUuid(data.uuid);
|
||||||
if (item?.type === 'feature') {
|
if (item?.type === 'feature') {
|
||||||
const current = this.document.system.features.map(x => x.uuid);
|
await this.document.update({
|
||||||
await this.document.update({ 'system.features': [...current, item.uuid] });
|
'system.features': [...this.document.system.features, { type: target.dataset.type, item }].map(x => ({
|
||||||
|
...x,
|
||||||
|
item: x.item?.uuid
|
||||||
|
}))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,7 @@ import DHHeritageSheet from '../api/heritage-sheet.mjs';
|
||||||
export default class AncestrySheet extends DHHeritageSheet {
|
export default class AncestrySheet extends DHHeritageSheet {
|
||||||
/**@inheritdoc */
|
/**@inheritdoc */
|
||||||
static DEFAULT_OPTIONS = {
|
static DEFAULT_OPTIONS = {
|
||||||
classes: ['ancestry'],
|
classes: ['ancestry']
|
||||||
actions: {
|
|
||||||
editFeature: AncestrySheet.#editFeature,
|
|
||||||
removeFeature: AncestrySheet.#removeFeature
|
|
||||||
},
|
|
||||||
dragDrop: [{ dragSelector: null, dropSelector: '.tab.features .drop-section' }]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**@inheritdoc */
|
/**@inheritdoc */
|
||||||
|
|
@ -18,38 +13,9 @@ export default class AncestrySheet extends DHHeritageSheet {
|
||||||
features: { template: 'systems/daggerheart/templates/sheets/items/ancestry/features.hbs' }
|
features: { template: 'systems/daggerheart/templates/sheets/items/ancestry/features.hbs' }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/**@inheritdoc */
|
||||||
/* Application Clicks Actions */
|
get relatedDocs() {
|
||||||
/* -------------------------------------------- */
|
return this.document.system.features.map(x => x.item);
|
||||||
|
|
||||||
/**
|
|
||||||
* Edit an existing feature on the item
|
|
||||||
* @type {ApplicationClickAction}
|
|
||||||
*/
|
|
||||||
static async #editFeature(_event, button) {
|
|
||||||
const target = button.closest('.feature-item');
|
|
||||||
const feature = this.document.system[`${target.dataset.type}Feature`];
|
|
||||||
if (!feature || Object.keys(feature).length === 0) {
|
|
||||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureIsMissing'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
feature.sheet.render(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a feature from the item.
|
|
||||||
* @type {ApplicationClickAction}
|
|
||||||
*/
|
|
||||||
static async #removeFeature(event, button) {
|
|
||||||
event.stopPropagation();
|
|
||||||
const target = button.closest('.feature-item');
|
|
||||||
const feature = this.document.system[`${target.dataset.type}Feature`];
|
|
||||||
|
|
||||||
if (feature) await feature.update({ 'system.subType': null });
|
|
||||||
await this.document.update({
|
|
||||||
'system.features': this.document.system.features.filter(x => x && x.uuid !== feature.uuid).map(x => x.uuid)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
@ -61,22 +27,12 @@ export default class AncestrySheet extends DHHeritageSheet {
|
||||||
* @param {DragEvent} event - The drag event
|
* @param {DragEvent} event - The drag event
|
||||||
*/
|
*/
|
||||||
async _onDrop(event) {
|
async _onDrop(event) {
|
||||||
event.stopPropagation();
|
const target = event.target.closest('fieldset.drop-section');
|
||||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
|
const typeField =
|
||||||
|
this.document.system[target.dataset.type === 'primary' ? 'primaryFeature' : 'secondaryFeature'];
|
||||||
|
|
||||||
const item = await fromUuid(data.uuid);
|
if (!typeField) {
|
||||||
if (item?.type === 'feature') {
|
super._onDrop(event);
|
||||||
const subType = event.target.closest('.primary-feature') ? 'primary' : 'secondary';
|
|
||||||
if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes[subType]) {
|
|
||||||
const error = subType === 'primary' ? 'featureNotPrimary' : 'featureNotSecondary';
|
|
||||||
ui.notifications.warn(game.i18n.localize(`DAGGERHEART.UI.Notifications.${error}`));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await item.update({ 'system.subType': subType });
|
|
||||||
await this.document.update({
|
|
||||||
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,11 @@ export default class BeastformSheet extends DHBaseItemSheet {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**@inheritdoc */
|
||||||
|
get relatedDocs() {
|
||||||
|
return this.document.system.features;
|
||||||
|
}
|
||||||
|
|
||||||
_attachPartListeners(partId, htmlElement, options) {
|
_attachPartListeners(partId, htmlElement, options) {
|
||||||
super._attachPartListeners(partId, htmlElement, options);
|
super._attachPartListeners(partId, htmlElement, options);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,31 @@ export default class ClassSheet extends DHBaseItemSheet {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**@inheritdoc */
|
||||||
|
get relatedDocs() {
|
||||||
|
return this.document.system.features.map(x => x.item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@inheritdoc */
|
||||||
|
async _onFirstRender(context, options) {
|
||||||
|
await super._onFirstRender(context, options);
|
||||||
|
|
||||||
|
const paths = [
|
||||||
|
'subclasses',
|
||||||
|
'characterGuide.suggestedPrimaryWeapon',
|
||||||
|
'characterGuide.suggestedSecondaryWeapon',
|
||||||
|
'characterGuide.suggestedArmor',
|
||||||
|
'inventory.take',
|
||||||
|
'inventory.choiceA',
|
||||||
|
'inventory.choiceB'
|
||||||
|
];
|
||||||
|
|
||||||
|
paths.forEach(path => {
|
||||||
|
const docs = [].concat(foundry.utils.getProperty(this.document, `system.${path}`) ?? []);
|
||||||
|
docs.forEach(doc => (doc.apps[this.id] = this));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**@inheritdoc */
|
/**@inheritdoc */
|
||||||
async _prepareContext(_options) {
|
async _prepareContext(_options) {
|
||||||
const context = await super._prepareContext(_options);
|
const context = await super._prepareContext(_options);
|
||||||
|
|
@ -87,69 +112,45 @@ export default class ClassSheet extends DHBaseItemSheet {
|
||||||
'system.subclasses': [...this.document.system.subclasses.map(x => x.uuid), item.uuid]
|
'system.subclasses': [...this.document.system.subclasses.map(x => x.uuid), item.uuid]
|
||||||
});
|
});
|
||||||
} else if (item.type === 'feature') {
|
} else if (item.type === 'feature') {
|
||||||
if (target.classList.contains('hope-feature')) {
|
super._onDrop(event);
|
||||||
if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes.hope) {
|
|
||||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureNotHope'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await item.update({ 'system.subType': CONFIG.DH.ITEM.featureSubTypes.hope });
|
|
||||||
await this.document.update({
|
|
||||||
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
|
|
||||||
});
|
|
||||||
} else if (target.classList.contains('class-feature')) {
|
|
||||||
if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes.class) {
|
|
||||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureNotClass'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await item.update({ 'system.subType': CONFIG.DH.ITEM.featureSubTypes.class });
|
|
||||||
await this.document.update({
|
|
||||||
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (item.type === 'weapon') {
|
} else if (item.type === 'weapon') {
|
||||||
if (target.classList.contains('primary-weapon-section')) {
|
if (target.classList.contains('primary-weapon-section')) {
|
||||||
if (!this.document.system.characterGuide.suggestedPrimaryWeapon && !item.system.secondary)
|
if (!item.system.secondary)
|
||||||
await this.document.update({
|
await this.document.update({
|
||||||
'system.characterGuide.suggestedPrimaryWeapon': item.uuid
|
'system.characterGuide.suggestedPrimaryWeapon': item.uuid
|
||||||
});
|
});
|
||||||
} else if (target.classList.contains('secondary-weapon-section')) {
|
} else if (target.classList.contains('secondary-weapon-section')) {
|
||||||
if (!this.document.system.characterGuide.suggestedSecondaryWeapon && item.system.secondary)
|
if (item.system.secondary)
|
||||||
await this.document.update({
|
await this.document.update({
|
||||||
'system.characterGuide.suggestedSecondaryWeapon': item.uuid
|
'system.characterGuide.suggestedSecondaryWeapon': item.uuid
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (item.type === 'armor') {
|
} else if (item.type === 'armor') {
|
||||||
if (target.classList.contains('armor-section')) {
|
if (target.classList.contains('armor-section')) {
|
||||||
if (!this.document.system.characterGuide.suggestedArmor)
|
await this.document.update({
|
||||||
await this.document.update({
|
'system.characterGuide.suggestedArmor': item.uuid
|
||||||
'system.characterGuide.suggestedArmor': item.uuid
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} else if (target.classList.contains('choice-a-section')) {
|
} else if (target.classList.contains('choice-a-section')) {
|
||||||
if (item.type === 'miscellaneous' || item.type === 'consumable') {
|
if (item.type === 'miscellaneous' || item.type === 'consumable') {
|
||||||
if (this.document.system.inventory.choiceA.length < 2)
|
const filteredChoiceA = this.document.system.inventory.choiceA;
|
||||||
|
if (filteredChoiceA.length < 2)
|
||||||
await this.document.update({
|
await this.document.update({
|
||||||
'system.inventory.choiceA': [
|
'system.inventory.choiceA': [...filteredChoiceA.map(x => x.uuid), item.uuid]
|
||||||
...this.document.system.inventory.choiceA.map(x => x.uuid),
|
|
||||||
item.uuid
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (item.type === 'miscellaneous') {
|
} else if (item.type === 'miscellaneous') {
|
||||||
if (target.classList.contains('take-section')) {
|
if (target.classList.contains('take-section')) {
|
||||||
if (this.document.system.inventory.take.length < 3)
|
const filteredTake = this.document.system.inventory.take.filter(x => x);
|
||||||
|
if (filteredTake.length < 3)
|
||||||
await this.document.update({
|
await this.document.update({
|
||||||
'system.inventory.take': [...this.document.system.inventory.take.map(x => x.uuid), item.uuid]
|
'system.inventory.take': [...filteredTake.map(x => x.uuid), item.uuid]
|
||||||
});
|
});
|
||||||
} else if (target.classList.contains('choice-b-section')) {
|
} else if (target.classList.contains('choice-b-section')) {
|
||||||
if (this.document.system.inventory.choiceB.length < 2)
|
const filteredChoiceB = this.document.system.inventory.choiceB.filter(x => x);
|
||||||
|
if (filteredChoiceB.length < 2)
|
||||||
await this.document.update({
|
await this.document.update({
|
||||||
'system.inventory.choiceB': [
|
'system.inventory.choiceB': [...filteredChoiceB.map(x => x.uuid), item.uuid]
|
||||||
...this.document.system.inventory.choiceB.map(x => x.uuid),
|
|
||||||
item.uuid
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -167,7 +168,7 @@ export default class ClassSheet extends DHBaseItemSheet {
|
||||||
static async #removeItemFromCollection(_event, element) {
|
static async #removeItemFromCollection(_event, element) {
|
||||||
const { uuid, target } = element.dataset;
|
const { uuid, target } = element.dataset;
|
||||||
const prop = foundry.utils.getProperty(this.document.system, target);
|
const prop = foundry.utils.getProperty(this.document.system, target);
|
||||||
await this.document.update({ [`system.${target}`]: prop.filter(i => i.uuid !== uuid) });
|
await this.document.update({ [`system.${target}`]: prop.filter(i => i.uuid !== uuid).map(x => x.uuid) });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -15,4 +15,9 @@ export default class CommunitySheet extends DHHeritageSheet {
|
||||||
scrollable: ['.feature']
|
scrollable: ['.feature']
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**@inheritdoc */
|
||||||
|
get relatedDocs() {
|
||||||
|
return this.document.system.features;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,7 @@ export default class SubclassSheet extends DHBaseItemSheet {
|
||||||
static DEFAULT_OPTIONS = {
|
static DEFAULT_OPTIONS = {
|
||||||
classes: ['subclass'],
|
classes: ['subclass'],
|
||||||
position: { width: 600 },
|
position: { width: 600 },
|
||||||
window: { resizable: false },
|
window: { resizable: false }
|
||||||
actions: {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**@override */
|
/**@override */
|
||||||
|
|
@ -37,62 +36,8 @@ export default class SubclassSheet extends DHBaseItemSheet {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
async _onDragStart(event) {
|
/**@inheritdoc */
|
||||||
const featureItem = event.currentTarget.closest('.drop-section');
|
get relatedDocs() {
|
||||||
|
return this.document.system.features.map(x => x.item);
|
||||||
if (featureItem) {
|
|
||||||
const feature = this.document.system[featureItem.dataset.type];
|
|
||||||
if (!feature) {
|
|
||||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureIsMissing'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const featureData = { type: 'Item', data: { ...feature.toObject(), _id: null }, fromInternal: true };
|
|
||||||
event.dataTransfer.setData('text/plain', JSON.stringify(featureData));
|
|
||||||
event.dataTransfer.setDragImage(featureItem.querySelector('img'), 60, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async _onDrop(event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
|
|
||||||
if (data.fromInternal) return;
|
|
||||||
|
|
||||||
const item = await fromUuid(data.uuid);
|
|
||||||
const target = event.target.closest('fieldset.drop-section');
|
|
||||||
if (item.type === 'feature') {
|
|
||||||
if (target.dataset.type === 'foundation') {
|
|
||||||
if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes.foundation) {
|
|
||||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureNotFoundation'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await item.update({ 'system.subType': CONFIG.DH.ITEM.featureSubTypes.foundation });
|
|
||||||
await this.document.update({
|
|
||||||
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
|
|
||||||
});
|
|
||||||
} else if (target.dataset.type === 'specialization') {
|
|
||||||
if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes.specialization) {
|
|
||||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureNotSpecialization'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await item.update({ 'system.subType': CONFIG.DH.ITEM.featureSubTypes.specialization });
|
|
||||||
await this.document.update({
|
|
||||||
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
|
|
||||||
});
|
|
||||||
} else if (target.dataset.type === 'mastery') {
|
|
||||||
if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes.mastery) {
|
|
||||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureNotMastery'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await item.update({ 'system.subType': CONFIG.DH.ITEM.featureSubTypes.mastery });
|
|
||||||
await this.document.update({
|
|
||||||
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -255,7 +255,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
||||||
const action = message.system.actions[Number.parseInt(event.currentTarget.dataset.index)];
|
const action = message.system.actions[Number.parseInt(event.currentTarget.dataset.index)];
|
||||||
const actor = game.actors.get(message.system.source.actor);
|
const actor = game.actors.get(message.system.source.actor);
|
||||||
await actor.use(action);
|
await actor.use(action);
|
||||||
};
|
}
|
||||||
|
|
||||||
async actionUseButton(event, message) {
|
async actionUseButton(event, message) {
|
||||||
const { moveIndex, actionIndex } = event.currentTarget.dataset;
|
const { moveIndex, actionIndex } = event.currentTarget.dataset;
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
|
|
||||||
this.extraSchemas.forEach(s => {
|
this.extraSchemas.forEach(s => {
|
||||||
let clsField;
|
let clsField;
|
||||||
if(clsField = this.getActionField(s)) schemaFields[s] = new clsField();
|
if ((clsField = this.getActionField(s))) schemaFields[s] = new clsField();
|
||||||
});
|
});
|
||||||
|
|
||||||
return schemaFields;
|
return schemaFields;
|
||||||
|
|
@ -117,14 +117,14 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
async use(event, ...args) {
|
async use(event, ...args) {
|
||||||
if (!this.actor) throw new Error("An Action can't be used outside of an Actor context.");
|
if (!this.actor) throw new Error("An Action can't be used outside of an Actor context.");
|
||||||
|
|
||||||
if(this.chatDisplay) this.toChat();
|
if (this.chatDisplay) this.toChat();
|
||||||
|
|
||||||
let config = this.prepareConfig(event);
|
let config = this.prepareConfig(event);
|
||||||
for(let i = 0; i < this.constructor.extraSchemas.length; i++) {
|
for (let i = 0; i < this.constructor.extraSchemas.length; i++) {
|
||||||
let clsField = this.constructor.getActionField(this.constructor.extraSchemas[i]);
|
let clsField = this.constructor.getActionField(this.constructor.extraSchemas[i]);
|
||||||
if(clsField?.prepareConfig) {
|
if (clsField?.prepareConfig) {
|
||||||
const keep = clsField.prepareConfig.call(this, config);
|
const keep = clsField.prepareConfig.call(this, config);
|
||||||
if(config.isFastForward && !keep) return;
|
if (config.isFastForward && !keep) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ export default class DHEffectAction extends DHBaseAction {
|
||||||
static extraSchemas = [...super.extraSchemas, 'effects', 'target'];
|
static extraSchemas = [...super.extraSchemas, 'effects', 'target'];
|
||||||
|
|
||||||
async trigger(event, data) {
|
async trigger(event, data) {
|
||||||
if(this.effects.length) {
|
if (this.effects.length) {
|
||||||
const cls = getDocumentClass('ChatMessage'),
|
const cls = getDocumentClass('ChatMessage'),
|
||||||
msg = {
|
msg = {
|
||||||
type: 'applyEffect',
|
type: 'applyEffect',
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,9 @@ export default class BeastformEffect extends foundry.abstract.TypeDataModel {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onCreate() {
|
async _onCreate(_data, _options, userId) {
|
||||||
|
if (userId !== game.user.id) return;
|
||||||
|
|
||||||
if (this.parent.parent?.type === 'character') {
|
if (this.parent.parent?.type === 'character') {
|
||||||
this.parent.parent.system.primaryWeapon?.update?.({ 'system.equipped': false });
|
this.parent.parent.system.primaryWeapon?.update?.({ 'system.equipped': false });
|
||||||
this.parent.parent.system.secondayWeapon?.update?.({ 'system.equipped': false });
|
this.parent.parent.system.secondayWeapon?.update?.({ 'system.equipped': false });
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,8 @@ export default class DhCharacter extends BaseDataActor {
|
||||||
}
|
}
|
||||||
|
|
||||||
get tier() {
|
get tier() {
|
||||||
return this.levelData.level.current === 1
|
const currentLevel = this.levelData.level.current;
|
||||||
|
return currentLevel === 1
|
||||||
? 1
|
? 1
|
||||||
: Object.values(game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers).find(
|
: Object.values(game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers).find(
|
||||||
tier => currentLevel >= tier.levels.start && currentLevel <= tier.levels.end
|
tier => currentLevel >= tier.levels.start && currentLevel <= tier.levels.end
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,9 @@ export default class DHAdversaryRoll extends foundry.abstract.TypeDataModel {
|
||||||
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
|
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
|
||||||
this.currentTargets =
|
this.currentTargets =
|
||||||
this.targetSelection !== true
|
this.targetSelection !== true
|
||||||
? Array.from(game.user.targets).map(t => game.system.api.fields.ActionFields.TargetField.formatTarget(t))
|
? Array.from(game.user.targets).map(t =>
|
||||||
|
game.system.api.fields.ActionFields.TargetField.formatTarget(t)
|
||||||
|
)
|
||||||
: this.targets;
|
: this.targets;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,9 @@ export default class DHApplyEffect extends foundry.abstract.TypeDataModel {
|
||||||
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
|
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
|
||||||
this.currentTargets =
|
this.currentTargets =
|
||||||
this.targetSelection !== true
|
this.targetSelection !== true
|
||||||
? Array.from(game.user.targets).map(t => game.system.api.fields.ActionFields.TargetField.formatTarget(t))
|
? Array.from(game.user.targets).map(t =>
|
||||||
|
game.system.api.fields.ActionFields.TargetField.formatTarget(t)
|
||||||
|
)
|
||||||
: this.targets;
|
: this.targets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,9 @@ export default class DHDamageRoll extends foundry.abstract.TypeDataModel {
|
||||||
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
|
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
|
||||||
this.currentTargets =
|
this.currentTargets =
|
||||||
this.targetSelection !== true
|
this.targetSelection !== true
|
||||||
? Array.from(game.user.targets).map(t => game.system.api.fields.ActionFields.TargetField.formatTarget(t))
|
? Array.from(game.user.targets).map(t =>
|
||||||
|
game.system.api.fields.ActionFields.TargetField.formatTarget(t)
|
||||||
|
)
|
||||||
: this.targets;
|
: this.targets;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,4 @@ export { default as SaveField } from './saveField.mjs';
|
||||||
export { default as BeastformField } from './beastformField.mjs';
|
export { default as BeastformField } from './beastformField.mjs';
|
||||||
export { default as DamageField } from './damageField.mjs';
|
export { default as DamageField } from './damageField.mjs';
|
||||||
export { default as HealingField } from './healingField.mjs';
|
export { default as HealingField } from './healingField.mjs';
|
||||||
export { default as RollField } from './rollField.mjs';
|
export { default as RollField } from './rollField.mjs';
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
export default class BeastformField extends fields.SchemaField {
|
export default class BeastformField extends fields.SchemaField {
|
||||||
constructor(options={}, context={}) {
|
constructor(options = {}, context = {}) {
|
||||||
const beastformFields = {
|
const beastformFields = {
|
||||||
tierAccess: new fields.SchemaField({
|
tierAccess: new fields.SchemaField({
|
||||||
exact: new fields.NumberField({ integer: true, nullable: true, initial: null })
|
exact: new fields.NumberField({ integer: true, nullable: true, initial: null })
|
||||||
|
|
@ -9,4 +9,4 @@ export default class BeastformField extends fields.SchemaField {
|
||||||
};
|
};
|
||||||
super(beastformFields, options, context);
|
super(beastformFields, options, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
export default class CostField extends fields.ArrayField {
|
export default class CostField extends fields.ArrayField {
|
||||||
constructor(options={}, context={}) {
|
constructor(options = {}, context = {}) {
|
||||||
const element = new fields.SchemaField({
|
const element = new fields.SchemaField({
|
||||||
key: new fields.StringField({
|
key: new fields.StringField({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|
@ -20,7 +20,7 @@ export default class CostField extends fields.ArrayField {
|
||||||
const costs = this.cost?.length ? foundry.utils.deepClone(this.cost) : [];
|
const costs = this.cost?.length ? foundry.utils.deepClone(this.cost) : [];
|
||||||
config.costs = CostField.calcCosts.call(this, costs);
|
config.costs = CostField.calcCosts.call(this, costs);
|
||||||
const hasCost = CostField.hasCost.call(this, config.costs);
|
const hasCost = CostField.hasCost.call(this, config.costs);
|
||||||
if(config.isFastForward && !hasCost)
|
if (config.isFastForward && !hasCost)
|
||||||
return ui.notifications.warn("You don't have the resources to use that action.");
|
return ui.notifications.warn("You don't have the resources to use that action.");
|
||||||
return hasCost;
|
return hasCost;
|
||||||
}
|
}
|
||||||
|
|
@ -79,4 +79,4 @@ export default class CostField extends fields.ArrayField {
|
||||||
const realCosts = costs?.length ? costs.filter(c => c.enabled) : [];
|
const realCosts = costs?.length ? costs.filter(c => c.enabled) : [];
|
||||||
return realCosts;
|
return realCosts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import FormulaField from "../formulaField.mjs";
|
import FormulaField from '../formulaField.mjs';
|
||||||
|
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
|
|
@ -81,4 +81,4 @@ export class DHDamageData extends DHResourceData {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
export default class EffectsField extends fields.ArrayField {
|
export default class EffectsField extends fields.ArrayField {
|
||||||
constructor(options={}, context={}) {
|
constructor(options = {}, context = {}) {
|
||||||
const element = new fields.SchemaField({
|
const element = new fields.SchemaField({
|
||||||
_id: new fields.DocumentIdField(),
|
_id: new fields.DocumentIdField(),
|
||||||
onSave: new fields.BooleanField({ initial: false })
|
onSave: new fields.BooleanField({ initial: false })
|
||||||
});
|
});
|
||||||
super(element, options, context);
|
super(element, options, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { DHDamageData } from "./damageField.mjs";
|
import { DHDamageData } from './damageField.mjs';
|
||||||
|
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
|
|
@ -6,4 +6,4 @@ export default class HealingField extends fields.EmbeddedDataField {
|
||||||
constructor(options, context = {}) {
|
constructor(options, context = {}) {
|
||||||
super(DHDamageData, options, context);
|
super(DHDamageData, options, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
export default class RangeField extends fields.StringField {
|
export default class RangeField extends fields.StringField {
|
||||||
constructor(context={}) {
|
constructor(context = {}) {
|
||||||
const options = {
|
const options = {
|
||||||
choices: CONFIG.DH.GENERAL.range,
|
choices: CONFIG.DH.GENERAL.range,
|
||||||
required: false,
|
required: false,
|
||||||
|
|
@ -13,4 +13,4 @@ export default class RangeField extends fields.StringField {
|
||||||
static prepareConfig(config) {
|
static prepareConfig(config) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,4 +55,4 @@ export default class RollField extends fields.EmbeddedDataField {
|
||||||
constructor(options, context = {}) {
|
constructor(options, context = {}) {
|
||||||
super(DHActionRollData, options, context);
|
super(DHActionRollData, options, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
export default class SaveField extends fields.SchemaField {
|
export default class SaveField extends fields.SchemaField {
|
||||||
constructor(options={}, context={}) {
|
constructor(options = {}, context = {}) {
|
||||||
const saveFields = {
|
const saveFields = {
|
||||||
trait: new fields.StringField({
|
trait: new fields.StringField({
|
||||||
nullable: true,
|
nullable: true,
|
||||||
|
|
@ -16,4 +16,4 @@ export default class SaveField extends fields.SchemaField {
|
||||||
};
|
};
|
||||||
super(saveFields, options, context);
|
super(saveFields, options, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
export default class TargetField extends fields.SchemaField {
|
export default class TargetField extends fields.SchemaField {
|
||||||
constructor(options={}, context={}) {
|
constructor(options = {}, context = {}) {
|
||||||
const targetFields = {
|
const targetFields = {
|
||||||
type: new fields.StringField({
|
type: new fields.StringField({
|
||||||
choices: CONFIG.DH.ACTIONS.targetTypes,
|
choices: CONFIG.DH.ACTIONS.targetTypes,
|
||||||
|
|
@ -26,13 +26,13 @@ export default class TargetField extends fields.SchemaField {
|
||||||
}
|
}
|
||||||
config.targets = targets.map(t => TargetField.formatTarget.call(this, t));
|
config.targets = targets.map(t => TargetField.formatTarget.call(this, t));
|
||||||
const hasTargets = TargetField.checkTargets.call(this, this.target.amount, config.targets);
|
const hasTargets = TargetField.checkTargets.call(this, this.target.amount, config.targets);
|
||||||
if(config.isFastForward && !hasTargets)
|
if (config.isFastForward && !hasTargets)
|
||||||
return ui.notifications.warn('Too many targets selected for that actions.');
|
return ui.notifications.warn('Too many targets selected for that actions.');
|
||||||
return hasTargets;
|
return hasTargets;
|
||||||
}
|
}
|
||||||
|
|
||||||
static checkTargets(amount, targets) {
|
static checkTargets(amount, targets) {
|
||||||
return true
|
return true;
|
||||||
// return !amount || (targets.length > amount);
|
// return !amount || (targets.length > amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,4 +59,4 @@ export default class TargetField extends fields.SchemaField {
|
||||||
evasion: actor.actor.system.evasion
|
evasion: actor.actor.system.evasion
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
export default class UsesField extends fields.SchemaField {
|
export default class UsesField extends fields.SchemaField {
|
||||||
constructor(options={}, context={}) {
|
constructor(options = {}, context = {}) {
|
||||||
const usesFields = {
|
const usesFields = {
|
||||||
value: new fields.NumberField({ nullable: true, initial: null }),
|
value: new fields.NumberField({ nullable: true, initial: null }),
|
||||||
max: new fields.NumberField({ nullable: true, initial: null }),
|
max: new fields.NumberField({ nullable: true, initial: null }),
|
||||||
|
|
@ -19,8 +19,7 @@ export default class UsesField extends fields.SchemaField {
|
||||||
if (uses && !uses.value) uses.value = 0;
|
if (uses && !uses.value) uses.value = 0;
|
||||||
config.uses = uses;
|
config.uses = uses;
|
||||||
const hasUses = UsesField.hasUses.call(this, config.uses);
|
const hasUses = UsesField.hasUses.call(this, config.uses);
|
||||||
if(config.isFastForward && !hasUses)
|
if (config.isFastForward && !hasUses) return ui.notifications.warn("That action doesn't have remaining uses.");
|
||||||
return ui.notifications.warn("That action doesn't have remaining uses.");
|
|
||||||
return hasUses;
|
return hasUses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,4 +35,4 @@ export default class UsesField extends fields.SchemaField {
|
||||||
if (!uses) return true;
|
if (!uses) return true;
|
||||||
return (uses.hasOwnProperty('enabled') && !uses.enabled) || uses.value + 1 <= uses.max;
|
return (uses.hasOwnProperty('enabled') && !uses.enabled) || uses.value + 1 <= uses.max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
19
module/data/fields/itemLinkFields.mjs
Normal file
19
module/data/fields/itemLinkFields.mjs
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import ForeignDocumentUUIDField from './foreignDocumentUUIDField.mjs';
|
||||||
|
|
||||||
|
export default class ItemLinkFields extends foundry.data.fields.ArrayField {
|
||||||
|
constructor(options, context) {
|
||||||
|
super(new ItemLinkField(), options, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ItemLinkField extends foundry.data.fields.SchemaField {
|
||||||
|
constructor(context) {
|
||||||
|
super(
|
||||||
|
{
|
||||||
|
type: new foundry.data.fields.StringField({ choices: CONFIG.DH.ITEM.featureSubTypes, nullable: true }),
|
||||||
|
item: new ForeignDocumentUUIDField({ type: 'Item' })
|
||||||
|
},
|
||||||
|
context
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,120 +9,120 @@
|
||||||
* by `options.initialKeys`?
|
* by `options.initialKeys`?
|
||||||
*/
|
*/
|
||||||
export default class MappingField extends foundry.data.fields.ObjectField {
|
export default class MappingField extends foundry.data.fields.ObjectField {
|
||||||
constructor(model, options) {
|
constructor(model, options) {
|
||||||
if ( !(model instanceof foundry.data.fields.DataField) ) {
|
if (!(model instanceof foundry.data.fields.DataField)) {
|
||||||
throw new Error("MappingField must have a DataField as its contained element");
|
throw new Error('MappingField must have a DataField as its contained element');
|
||||||
|
}
|
||||||
|
super(options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The embedded DataField definition which is contained in this field.
|
||||||
|
* @type {DataField}
|
||||||
|
*/
|
||||||
|
this.model = model;
|
||||||
|
model.parent = this;
|
||||||
}
|
}
|
||||||
super(options);
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
static get _defaults() {
|
||||||
|
return foundry.utils.mergeObject(super._defaults, {
|
||||||
|
initialKeys: null,
|
||||||
|
initialValue: null,
|
||||||
|
initialKeysOnly: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
_cleanType(value, options) {
|
||||||
|
Object.entries(value).forEach(([k, v]) => {
|
||||||
|
if (k.startsWith('-=')) return;
|
||||||
|
value[k] = this.model.clean(v, options);
|
||||||
|
});
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
getInitialValue(data) {
|
||||||
|
let keys = this.initialKeys;
|
||||||
|
const initial = super.getInitialValue(data);
|
||||||
|
if (!keys || !foundry.utils.isEmpty(initial)) return initial;
|
||||||
|
if (!(keys instanceof Array)) keys = Object.keys(keys);
|
||||||
|
for (const key of keys) initial[key] = this._getInitialValueForKey(key);
|
||||||
|
return initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The embedded DataField definition which is contained in this field.
|
* Get the initial value for the provided key.
|
||||||
* @type {DataField}
|
* @param {string} key Key within the object being built.
|
||||||
|
* @param {object} [object] Any existing mapping data.
|
||||||
|
* @returns {*} Initial value based on provided field type.
|
||||||
*/
|
*/
|
||||||
this.model = model;
|
_getInitialValueForKey(key, object) {
|
||||||
model.parent = this;
|
const initial = this.model.getInitialValue();
|
||||||
}
|
return this.initialValue?.(key, initial, object) ?? initial;
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/** @inheritDoc */
|
|
||||||
static get _defaults() {
|
|
||||||
return foundry.utils.mergeObject(super._defaults, {
|
|
||||||
initialKeys: null,
|
|
||||||
initialValue: null,
|
|
||||||
initialKeysOnly: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/** @inheritDoc */
|
|
||||||
_cleanType(value, options) {
|
|
||||||
Object.entries(value).forEach(([k, v]) => {
|
|
||||||
if ( k.startsWith("-=") ) return;
|
|
||||||
value[k] = this.model.clean(v, options);
|
|
||||||
});
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/** @inheritDoc */
|
|
||||||
getInitialValue(data) {
|
|
||||||
let keys = this.initialKeys;
|
|
||||||
const initial = super.getInitialValue(data);
|
|
||||||
if ( !keys || !foundry.utils.isEmpty(initial) ) return initial;
|
|
||||||
if ( !(keys instanceof Array) ) keys = Object.keys(keys);
|
|
||||||
for ( const key of keys ) initial[key] = this._getInitialValueForKey(key);
|
|
||||||
return initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the initial value for the provided key.
|
|
||||||
* @param {string} key Key within the object being built.
|
|
||||||
* @param {object} [object] Any existing mapping data.
|
|
||||||
* @returns {*} Initial value based on provided field type.
|
|
||||||
*/
|
|
||||||
_getInitialValueForKey(key, object) {
|
|
||||||
const initial = this.model.getInitialValue();
|
|
||||||
return this.initialValue?.(key, initial, object) ?? initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/** @override */
|
|
||||||
_validateType(value, options={}) {
|
|
||||||
if ( foundry.utils.getType(value) !== "Object" ) throw new Error("must be an Object");
|
|
||||||
const errors = this._validateValues(value, options);
|
|
||||||
if ( !foundry.utils.isEmpty(errors) ) {
|
|
||||||
const failure = new foundry.data.validation.DataModelValidationFailure();
|
|
||||||
failure.elements = Object.entries(errors).map(([id, failure]) => ({ id, failure }));
|
|
||||||
throw failure.asError();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/** @override */
|
||||||
* Validate each value of the object.
|
_validateType(value, options = {}) {
|
||||||
* @param {object} value The object to validate.
|
if (foundry.utils.getType(value) !== 'Object') throw new Error('must be an Object');
|
||||||
* @param {object} options Validation options.
|
const errors = this._validateValues(value, options);
|
||||||
* @returns {Record<string, Error>} An object of value-specific errors by key.
|
if (!foundry.utils.isEmpty(errors)) {
|
||||||
*/
|
const failure = new foundry.data.validation.DataModelValidationFailure();
|
||||||
_validateValues(value, options) {
|
failure.elements = Object.entries(errors).map(([id, failure]) => ({ id, failure }));
|
||||||
const errors = {};
|
throw failure.asError();
|
||||||
for ( const [k, v] of Object.entries(value) ) {
|
}
|
||||||
if ( k.startsWith("-=") ) continue;
|
|
||||||
const error = this.model.validate(v, options);
|
|
||||||
if ( error ) errors[k] = error;
|
|
||||||
}
|
}
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/** @override */
|
/**
|
||||||
initialize(value, model, options={}) {
|
* Validate each value of the object.
|
||||||
if ( !value ) return value;
|
* @param {object} value The object to validate.
|
||||||
const obj = {};
|
* @param {object} options Validation options.
|
||||||
const initialKeys = (this.initialKeys instanceof Array) ? this.initialKeys : Object.keys(this.initialKeys ?? {});
|
* @returns {Record<string, Error>} An object of value-specific errors by key.
|
||||||
const keys = this.initialKeysOnly ? initialKeys : Object.keys(value);
|
*/
|
||||||
for ( const key of keys ) {
|
_validateValues(value, options) {
|
||||||
const data = value[key] ?? this._getInitialValueForKey(key, value);
|
const errors = {};
|
||||||
obj[key] = this.model.initialize(data, model, options);
|
for (const [k, v] of Object.entries(value)) {
|
||||||
|
if (k.startsWith('-=')) continue;
|
||||||
|
const error = this.model.validate(v, options);
|
||||||
|
if (error) errors[k] = error;
|
||||||
|
}
|
||||||
|
return errors;
|
||||||
}
|
}
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/** @inheritDoc */
|
/** @override */
|
||||||
_getField(path) {
|
initialize(value, model, options = {}) {
|
||||||
if ( path.length === 0 ) return this;
|
if (!value) return value;
|
||||||
else if ( path.length === 1 ) return this.model;
|
const obj = {};
|
||||||
path.shift();
|
const initialKeys = this.initialKeys instanceof Array ? this.initialKeys : Object.keys(this.initialKeys ?? {});
|
||||||
return this.model._getField(path);
|
const keys = this.initialKeysOnly ? initialKeys : Object.keys(value);
|
||||||
}
|
for (const key of keys) {
|
||||||
}
|
const data = value[key] ?? this._getInitialValueForKey(key, value);
|
||||||
|
obj[key] = this.model.initialize(data, model, options);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
_getField(path) {
|
||||||
|
if (path.length === 0) return this;
|
||||||
|
else if (path.length === 1) return this.model;
|
||||||
|
path.shift();
|
||||||
|
return this.model._getField(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs';
|
|
||||||
import BaseDataItem from './base.mjs';
|
import BaseDataItem from './base.mjs';
|
||||||
|
import ItemLinkFields from '../../data/fields/itemLinkFields.mjs';
|
||||||
|
|
||||||
export default class DHAncestry extends BaseDataItem {
|
export default class DHAncestry extends BaseDataItem {
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
|
|
@ -15,23 +15,15 @@ export default class DHAncestry extends BaseDataItem {
|
||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
return {
|
return {
|
||||||
...super.defineSchema(),
|
...super.defineSchema(),
|
||||||
features: new ForeignDocumentUUIDArrayField({ type: 'Item' })
|
features: new ItemLinkFields()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get primaryFeature() {
|
get primaryFeature() {
|
||||||
return (
|
return this.features.find(x => x.type === CONFIG.DH.ITEM.featureSubTypes.primary)?.item;
|
||||||
this.features.find(x => x?.system?.subType === CONFIG.DH.ITEM.featureSubTypes.primary) ??
|
|
||||||
(this.features.filter(x => !x).length > 0 ? {} : null)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get secondaryFeature() {
|
get secondaryFeature() {
|
||||||
return (
|
return this.features.find(x => x.type === CONFIG.DH.ITEM.featureSubTypes.secondary)?.item;
|
||||||
this.features.find(x => x?.system?.subType === CONFIG.DH.ITEM.featureSubTypes.secondary) ??
|
|
||||||
(this.features.filter(x => !x || x.system.subType === CONFIG.DH.ITEM.featureSubTypes.primary).length > 1
|
|
||||||
? {}
|
|
||||||
: null)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@
|
||||||
* @property {boolean} isInventoryItem- Indicates whether items of this type is a Inventory Item
|
* @property {boolean} isInventoryItem- Indicates whether items of this type is a Inventory Item
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ActionsField } from "../fields/actionField.mjs";
|
import { addLinkedItemsDiff, updateLinkedItemApps } from '../../helpers/utils.mjs';
|
||||||
|
import { ActionsField } from '../fields/actionField.mjs';
|
||||||
|
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
|
|
@ -72,8 +73,7 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
||||||
if (this.metadata.isQuantifiable)
|
if (this.metadata.isQuantifiable)
|
||||||
schema.quantity = new fields.NumberField({ integer: true, initial: 1, min: 0, required: true });
|
schema.quantity = new fields.NumberField({ integer: true, initial: 1, min: 0, required: true });
|
||||||
|
|
||||||
if (this.metadata.hasActions)
|
if (this.metadata.hasActions) schema.actions = new ActionsField();
|
||||||
schema.actions = new ActionsField()
|
|
||||||
|
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
|
|
@ -124,18 +124,21 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onCreate(data) {
|
_onCreate(data, _, userId) {
|
||||||
|
if (userId !== game.user.id) return;
|
||||||
|
|
||||||
if (!this.actor || this.actor.type !== 'character' || !this.features) return;
|
if (!this.actor || this.actor.type !== 'character' || !this.features) return;
|
||||||
|
|
||||||
this.actor.createEmbeddedDocuments(
|
this.actor.createEmbeddedDocuments(
|
||||||
'Item',
|
'Item',
|
||||||
this.features.map(feature => ({
|
this.features.map(feature => ({
|
||||||
...feature,
|
...(feature.item ?? feature),
|
||||||
system: {
|
system: {
|
||||||
...feature.system,
|
...(feature.item?.system ?? feature.system),
|
||||||
originItemType: this.parent.type,
|
originItemType: this.parent.type,
|
||||||
originId: data._id,
|
originId: data._id,
|
||||||
identifier: feature.identifier
|
identifier: feature.identifier,
|
||||||
|
subType: feature.item ? feature.type : undefined
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
@ -151,4 +154,17 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
||||||
items.map(x => x.id)
|
items.map(x => x.id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _preUpdate(changed, options, userId) {
|
||||||
|
const allowed = await super._preUpdate(changed, options, userId);
|
||||||
|
if (allowed === false) return false;
|
||||||
|
|
||||||
|
addLinkedItemsDiff(changed.system?.features, this.features, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onUpdate(changed, options, userId) {
|
||||||
|
super._onUpdate(changed, options, userId);
|
||||||
|
|
||||||
|
updateLinkedItemApps(options, this.parent.sheet);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,9 @@ export default class DHBeastform extends BaseDataItem {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_onCreate() {
|
_onCreate(_data, _options, userId) {
|
||||||
|
if (userId !== game.user.id) return;
|
||||||
|
|
||||||
this.parent.createEmbeddedDocuments('ActiveEffect', [
|
this.parent.createEmbeddedDocuments('ActiveEffect', [
|
||||||
{
|
{
|
||||||
type: 'beastform',
|
type: 'beastform',
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import BaseDataItem from './base.mjs';
|
import BaseDataItem from './base.mjs';
|
||||||
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
|
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
|
||||||
import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs';
|
import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs';
|
||||||
|
import ItemLinkFields from '../fields/itemLinkFields.mjs';
|
||||||
|
import { addLinkedItemsDiff, updateLinkedItemApps } from '../../helpers/utils.mjs';
|
||||||
|
|
||||||
export default class DHClass extends BaseDataItem {
|
export default class DHClass extends BaseDataItem {
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
|
|
@ -27,7 +29,7 @@ export default class DHClass extends BaseDataItem {
|
||||||
label: 'DAGGERHEART.GENERAL.HitPoints.plural'
|
label: 'DAGGERHEART.GENERAL.HitPoints.plural'
|
||||||
}),
|
}),
|
||||||
evasion: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.evasion' }),
|
evasion: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.evasion' }),
|
||||||
features: new ForeignDocumentUUIDArrayField({ type: 'Item' }),
|
features: new ItemLinkFields(),
|
||||||
subclasses: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
|
subclasses: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
|
||||||
inventory: new fields.SchemaField({
|
inventory: new fields.SchemaField({
|
||||||
take: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
|
take: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
|
||||||
|
|
@ -52,17 +54,11 @@ export default class DHClass extends BaseDataItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
get hopeFeatures() {
|
get hopeFeatures() {
|
||||||
return (
|
return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.hope).map(x => x.item);
|
||||||
this.features.filter(x => x?.system?.subType === CONFIG.DH.ITEM.featureSubTypes.hope) ??
|
|
||||||
(this.features.filter(x => !x).length > 0 ? {} : null)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get classFeatures() {
|
get classFeatures() {
|
||||||
return (
|
return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.class).map(x => x.item);
|
||||||
this.features.filter(x => x?.system?.subType === CONFIG.DH.ITEM.featureSubTypes.class) ??
|
|
||||||
(this.features.filter(x => !x).length > 0 ? {} : null)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async _preCreate(data, options, user) {
|
async _preCreate(data, options, user) {
|
||||||
|
|
@ -80,6 +76,9 @@ export default class DHClass extends BaseDataItem {
|
||||||
|
|
||||||
_onCreate(data, options, userId) {
|
_onCreate(data, options, userId) {
|
||||||
super._onCreate(data, options, userId);
|
super._onCreate(data, options, userId);
|
||||||
|
|
||||||
|
if (userId !== game.user.id) return;
|
||||||
|
|
||||||
if (options.parent?.type === 'character') {
|
if (options.parent?.type === 'character') {
|
||||||
const path = `system.${data.system.isMulticlass ? 'multiclass.value' : 'class.value'}`;
|
const path = `system.${data.system.isMulticlass ? 'multiclass.value' : 'class.value'}`;
|
||||||
options.parent.update({ [path]: `${options.parent.uuid}.Item.${data._id}` });
|
options.parent.update({ [path]: `${options.parent.uuid}.Item.${data._id}` });
|
||||||
|
|
@ -98,4 +97,33 @@ export default class DHClass extends BaseDataItem {
|
||||||
foundry.utils.getProperty(options.parent, `${path}.subclass`)?.delete();
|
foundry.utils.getProperty(options.parent, `${path}.subclass`)?.delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _preUpdate(changed, options, userId) {
|
||||||
|
const allowed = await super._preUpdate(changed, options, userId);
|
||||||
|
if (allowed === false) return false;
|
||||||
|
|
||||||
|
const paths = [
|
||||||
|
'subclasses',
|
||||||
|
'characterGuide.suggestedPrimaryWeapon',
|
||||||
|
'characterGuide.suggestedSecondaryWeapon',
|
||||||
|
'characterGuide.suggestedArmor',
|
||||||
|
'inventory.take',
|
||||||
|
'inventory.choiceA',
|
||||||
|
'inventory.choiceB'
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let path of paths) {
|
||||||
|
const currentItems = [].concat(foundry.utils.getProperty(this, path) ?? []);
|
||||||
|
const changedItems = [].concat(foundry.utils.getProperty(changed, `system.${path}`) ?? []);
|
||||||
|
if (!changedItems.length) continue;
|
||||||
|
|
||||||
|
addLinkedItemsDiff(changedItems, currentItems, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onUpdate(changed, options, userId) {
|
||||||
|
super._onUpdate(changed, options, userId);
|
||||||
|
|
||||||
|
updateLinkedItemApps(options, this.parent.sheet);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs';
|
import ItemLinkFields from '../fields/itemLinkFields.mjs';
|
||||||
import BaseDataItem from './base.mjs';
|
import BaseDataItem from './base.mjs';
|
||||||
|
|
||||||
export default class DHSubclass extends BaseDataItem {
|
export default class DHSubclass extends BaseDataItem {
|
||||||
|
|
@ -22,22 +22,22 @@ export default class DHSubclass extends BaseDataItem {
|
||||||
nullable: true,
|
nullable: true,
|
||||||
initial: null
|
initial: null
|
||||||
}),
|
}),
|
||||||
features: new ForeignDocumentUUIDArrayField({ type: 'Item' }),
|
features: new ItemLinkFields(),
|
||||||
featureState: new fields.NumberField({ required: true, initial: 1, min: 1 }),
|
featureState: new fields.NumberField({ required: true, initial: 1, min: 1 }),
|
||||||
isMulticlass: new fields.BooleanField({ initial: false })
|
isMulticlass: new fields.BooleanField({ initial: false })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get foundationFeatures() {
|
get foundationFeatures() {
|
||||||
return this.features.filter(x => x.system.subType === CONFIG.DH.ITEM.featureSubTypes.foundation);
|
return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.foundation).map(x => x.item);
|
||||||
}
|
}
|
||||||
|
|
||||||
get specializationFeatures() {
|
get specializationFeatures() {
|
||||||
return this.features.filter(x => x.system.subType === CONFIG.DH.ITEM.featureSubTypes.specialization);
|
return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.specialization).map(x => x.item);
|
||||||
}
|
}
|
||||||
|
|
||||||
get masteryFeatures() {
|
get masteryFeatures() {
|
||||||
return this.features.filter(x => x.system.subType === CONFIG.DH.ITEM.featureSubTypes.mastery);
|
return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.mastery).map(x => x.item);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _preCreate(data, options, user) {
|
async _preCreate(data, options, user) {
|
||||||
|
|
@ -67,6 +67,8 @@ export default class DHSubclass extends BaseDataItem {
|
||||||
_onCreate(data, options, userId) {
|
_onCreate(data, options, userId) {
|
||||||
super._onCreate(data, options, userId);
|
super._onCreate(data, options, userId);
|
||||||
|
|
||||||
|
if (userId !== game.user.id) return;
|
||||||
|
|
||||||
if (options.parent?.type === 'character') {
|
if (options.parent?.type === 'character') {
|
||||||
const path = `system.${data.system.isMulticlass ? 'multiclass.subclass' : 'class.subclass'}`;
|
const path = `system.${data.system.isMulticlass ? 'multiclass.subclass' : 'class.subclass'}`;
|
||||||
options.parent.update({ [path]: `${options.parent.uuid}.Item.${data._id}` });
|
options.parent.update({ [path]: `${options.parent.uuid}.Item.${data._id}` });
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ export default class DamageRoll extends DHRoll {
|
||||||
|
|
||||||
static async buildEvaluate(roll, config = {}, message = {}) {
|
static async buildEvaluate(roll, config = {}, message = {}) {
|
||||||
if (config.evaluate !== false) {
|
if (config.evaluate !== false) {
|
||||||
if(config.dialog.configure === false) roll.constructFormula(config);
|
if (config.dialog.configure === false) roll.constructFormula(config);
|
||||||
for (const roll of config.roll) await roll.roll.evaluate();
|
for (const roll of config.roll) await roll.roll.evaluate();
|
||||||
}
|
}
|
||||||
roll._evaluated = true;
|
roll._evaluated = true;
|
||||||
|
|
|
||||||
|
|
@ -26,15 +26,15 @@ export default class DhpActor extends Actor {
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
getEmbeddedDocument(embeddedName, id, options) {
|
getEmbeddedDocument(embeddedName, id, options) {
|
||||||
let doc;
|
let doc;
|
||||||
switch ( embeddedName ) {
|
switch (embeddedName) {
|
||||||
case "Action":
|
case 'Action':
|
||||||
doc = this.system.actions?.get(id);
|
doc = this.system.actions?.get(id);
|
||||||
if(!doc && this.system.attack?.id === id) doc = this.system.attack;
|
if (!doc && this.system.attack?.id === id) doc = this.system.attack;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return super.getEmbeddedDocument(embeddedName, id, options);
|
return super.getEmbeddedDocument(embeddedName, id, options);
|
||||||
}
|
}
|
||||||
if ( options?.strict && !doc ) {
|
if (options?.strict && !doc) {
|
||||||
throw new Error(`The key ${id} does not exist in the ${embeddedName} Collection`);
|
throw new Error(`The key ${id} does not exist in the ${embeddedName} Collection`);
|
||||||
}
|
}
|
||||||
return doc;
|
return doc;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import ActionSelectionDialog from "../applications/dialogs/actionSelectionDialog.mjs";
|
import ActionSelectionDialog from '../applications/dialogs/actionSelectionDialog.mjs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override and extend the basic Item implementation.
|
* Override and extend the basic Item implementation.
|
||||||
|
|
|
||||||
|
|
@ -8,19 +8,15 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
|
||||||
const item = await foundry.utils.fromUuid(itemUuid);
|
const item = await foundry.utils.fromUuid(itemUuid);
|
||||||
if (item) {
|
if (item) {
|
||||||
const isAction = item instanceof game.system.api.models.actions.actionsTypes.base;
|
const isAction = item instanceof game.system.api.models.actions.actionsTypes.base;
|
||||||
const description = await TextEditor.enrichHTML(isAction ? item.description : item.system.description);
|
const isEffect = item instanceof ActiveEffect;
|
||||||
if (item.system?.features) {
|
await this.enrichText(item, isAction || isEffect);
|
||||||
for (let feature of item.system.features) {
|
|
||||||
feature.system.enrichedDescription = await TextEditor.enrichHTML(feature.system.description);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const type = isAction ? 'action' : item.type;
|
const type = isAction ? 'action' : isEffect ? 'effect' : item.type;
|
||||||
html = await foundry.applications.handlebars.renderTemplate(
|
html = await foundry.applications.handlebars.renderTemplate(
|
||||||
`systems/daggerheart/templates/ui/tooltip/${type}.hbs`,
|
`systems/daggerheart/templates/ui/tooltip/${type}.hbs`,
|
||||||
{
|
{
|
||||||
item: item,
|
item: item,
|
||||||
description: description,
|
description: item.system?.enrichedDescription ?? item.enrichedDescription,
|
||||||
config: CONFIG.DH
|
config: CONFIG.DH
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -126,4 +122,37 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async enrichText(item, flatStructure) {
|
||||||
|
const { TextEditor } = foundry.applications.ux;
|
||||||
|
const enrichPaths = [
|
||||||
|
{ path: flatStructure ? '' : 'system', name: 'description' },
|
||||||
|
{ path: 'system', name: 'features' },
|
||||||
|
{ path: 'system', name: 'actions' },
|
||||||
|
{ path: 'system', name: 'customActions' }
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let data of enrichPaths) {
|
||||||
|
const basePath = `${data.path ? `${data.path}.` : ''}${data.name}`;
|
||||||
|
const pathValue = foundry.utils.getProperty(item, basePath);
|
||||||
|
if (!pathValue) continue;
|
||||||
|
|
||||||
|
if (Array.isArray(pathValue) || pathValue.size) {
|
||||||
|
for (const [index, itemValue] of pathValue.entries()) {
|
||||||
|
const itemIsAction = itemValue instanceof game.system.api.models.actions.actionsTypes.base;
|
||||||
|
const value = itemIsAction || !itemValue?.item ? itemValue : itemValue.item;
|
||||||
|
const enrichedValue = await TextEditor.enrichHTML(value.description);
|
||||||
|
if (itemIsAction) value.enrichedDescription = enrichedValue;
|
||||||
|
else foundry.utils.setProperty(item, `${basePath}.${index}.enrichedDescription`, enrichedValue);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const enrichedValue = await TextEditor.enrichHTML(pathValue);
|
||||||
|
foundry.utils.setProperty(
|
||||||
|
item,
|
||||||
|
`${data.path ? `${data.path}.` : ''}enriched${data.name.capitalize()}`,
|
||||||
|
enrichedValue
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -241,6 +241,50 @@ export function getDocFromElement(element) {
|
||||||
return foundry.utils.fromUuidSync(target.dataset.itemUuid) ?? null;
|
return foundry.utils.fromUuidSync(target.dataset.itemUuid) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the update diff on a linkedItem property to update.options for use
|
||||||
|
* in _onUpdate via the updateLinkedItemApps function.
|
||||||
|
* @param {Array} changedItems The candidate changed list
|
||||||
|
* @param {Array} currentItems The current list
|
||||||
|
* @param {object} options Additional options which modify the update request
|
||||||
|
*/
|
||||||
|
export function addLinkedItemsDiff(changedItems, currentItems, options) {
|
||||||
|
if (changedItems) {
|
||||||
|
const prevItems = new Set(currentItems);
|
||||||
|
const newItems = new Set(changedItems);
|
||||||
|
options.toLink = Array.from(
|
||||||
|
newItems
|
||||||
|
.difference(prevItems)
|
||||||
|
.map(item => item?.item ?? item)
|
||||||
|
.filter(x => (typeof x === 'object' ? x.item : x))
|
||||||
|
);
|
||||||
|
|
||||||
|
options.toUnlink = Array.from(
|
||||||
|
prevItems
|
||||||
|
.difference(newItems)
|
||||||
|
.map(item => item?.item?.uuid ?? item?.uuid ?? item)
|
||||||
|
.filter(x => (typeof x === 'object' ? x.item : x))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds or removes the current Application from linked document apps
|
||||||
|
* depending on an update diff in the linked item list.
|
||||||
|
* @param {object} options Additional options which modify the update requests
|
||||||
|
* @param {object} sheet The application to add or remove from document apps
|
||||||
|
*/
|
||||||
|
export function updateLinkedItemApps(options, sheet) {
|
||||||
|
options.toLink?.forEach(featureUuid => {
|
||||||
|
const doc = foundry.utils.fromUuidSync(featureUuid);
|
||||||
|
doc.apps[sheet.id] = sheet;
|
||||||
|
});
|
||||||
|
options.toUnlink?.forEach(featureUuid => {
|
||||||
|
const doc = foundry.utils.fromUuidSync(featureUuid);
|
||||||
|
delete doc.apps[sheet.id];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export const itemAbleRollParse = (value, actor, item) => {
|
export const itemAbleRollParse = (value, actor, item) => {
|
||||||
if (!value) return value;
|
if (!value) return value;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
@import '../../utils/fonts.less';
|
@import '../../utils/fonts.less';
|
||||||
|
|
||||||
.application.daggerheart.dh-style {
|
.application.daggerheart.dh-style {
|
||||||
|
.actions-list,
|
||||||
.actions-list, .action-buttons-list {
|
.action-buttons-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
|
@ -36,11 +36,11 @@
|
||||||
|
|
||||||
.action-item {
|
.action-item {
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: rgba(255,255,255,.05);
|
background-color: rgba(255, 255, 255, 0.05);
|
||||||
}
|
}
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
transition: background-color .3s ease-in-out;
|
transition: background-color 0.3s ease-in-out;
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="radio"] {
|
input[type='radio'] {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex: 1;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
@import '../../../utils/colors.less';
|
@import '../../../utils/colors.less';
|
||||||
@import '../../../utils/fonts.less';
|
@import '../../../utils/fonts.less';
|
||||||
|
|
||||||
.application.sheet.daggerheart.actor.dh-style.character {
|
.application.sheet.daggerheart.actor.dh-style.character {
|
||||||
.tab.effects {
|
.tab.effects {
|
||||||
.effects-sections {
|
.effects-sections {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%);
|
mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%);
|
||||||
padding: 20px 0;
|
padding: 20px 0;
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
|
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
|
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.selectArmor"}}
|
{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.selectArmor"}}
|
||||||
{{/"systems/daggerheart/templates/components/card-preview.hbs"}}
|
{{/"systems/daggerheart/templates/components/card-preview.hbs"}}
|
||||||
</div>
|
</div>
|
||||||
{{#if armor.suggestion}}
|
{{#if armor.suggestion.name}}
|
||||||
<fieldset class="suggestion-container">
|
<fieldset class="suggestion-container">
|
||||||
<legend>{{armor.suggestion.name}}</legend>
|
<legend>{{armor.suggestion.name}}</legend>
|
||||||
<div class="suggestion-inner-container {{#if armor.suggestion.taken}}taken{{/if}}" data-action="viewItem" data-uuid="{{armor.suggestion.uuid}}">
|
<div class="suggestion-inner-container {{#if armor.suggestion.taken}}taken{{/if}}" data-action="viewItem" data-uuid="{{armor.suggestion.uuid}}">
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.selectPrimaryWeapon"}}
|
{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.selectPrimaryWeapon"}}
|
||||||
{{/"systems/daggerheart/templates/components/card-preview.hbs"}}
|
{{/"systems/daggerheart/templates/components/card-preview.hbs"}}
|
||||||
</div>
|
</div>
|
||||||
{{#if primaryWeapon.suggestion}}
|
{{#if primaryWeapon.suggestion.name}}
|
||||||
<fieldset class="suggestion-container">
|
<fieldset class="suggestion-container">
|
||||||
<legend>{{primaryWeapon.suggestion.name}}</legend>
|
<legend>{{primaryWeapon.suggestion.name}}</legend>
|
||||||
<div class="suggestion-inner-container {{#if primaryWeapon.suggestion.taken}}taken{{/if}}" data-action="viewItem" data-uuid="{{primaryWeapon.suggestion.uuid}}">
|
<div class="suggestion-inner-container {{#if primaryWeapon.suggestion.taken}}taken{{/if}}" data-action="viewItem" data-uuid="{{primaryWeapon.suggestion.uuid}}">
|
||||||
|
|
@ -48,7 +48,7 @@
|
||||||
{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.selectSecondaryWeapon"}}
|
{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.selectSecondaryWeapon"}}
|
||||||
{{/"systems/daggerheart/templates/components/card-preview.hbs"}}
|
{{/"systems/daggerheart/templates/components/card-preview.hbs"}}
|
||||||
</div>
|
</div>
|
||||||
{{#if secondaryWeapon.suggestion}}
|
{{#if secondaryWeapon.suggestion.name}}
|
||||||
<fieldset class="suggestion-container">
|
<fieldset class="suggestion-container">
|
||||||
<legend>{{secondaryWeapon.suggestion.name}}</legend>
|
<legend>{{secondaryWeapon.suggestion.name}}</legend>
|
||||||
<div
|
<div
|
||||||
|
|
@ -63,45 +63,47 @@
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
<div class="main-equipment-selection triple">
|
{{#unless noInventoryChoices}}
|
||||||
<fieldset class="equipment-selection">
|
<div class="main-equipment-selection triple">
|
||||||
<legend>{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.startingItems"}}</legend>
|
<fieldset class="equipment-selection">
|
||||||
|
<legend>{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.startingItems"}}</legend>
|
||||||
|
|
||||||
<div class="simple-equipment-container">
|
<div class="simple-equipment-container">
|
||||||
{{#each inventory.take}}
|
{{#each inventory.take}}
|
||||||
<div class="simple-equipment">
|
<div class="simple-equipment">
|
||||||
<label>{{this.name}}</label>
|
<label>{{this.name}}</label>
|
||||||
<img src="{{this.img}}" />
|
<img src="{{this.img}}" />
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset class="equipment-selection">
|
<fieldset class="equipment-selection">
|
||||||
<legend>{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.choice"}}</legend>
|
<legend>{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.choice"}}</legend>
|
||||||
|
|
||||||
<div class="simple-equipment-container">
|
<div class="simple-equipment-container">
|
||||||
{{#each inventory.choiceA.suggestions}}
|
{{#each inventory.choiceA.suggestions}}
|
||||||
<div class="simple-equipment selectable {{#if (not this.selected)}}inactive{{/if}}" data-action="equipmentChoice" data-path="choiceA" data-uuid="{{this.uuid}}">
|
<div class="simple-equipment selectable {{#if (not this.selected)}}inactive{{/if}}" data-action="equipmentChoice" data-path="choiceA" data-uuid="{{this.uuid}}">
|
||||||
<label>{{this.name}}</label>
|
<label>{{this.name}}</label>
|
||||||
<img src="{{this.img}}" />
|
<img src="{{this.img}}" />
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset class="equipment-selection">
|
<fieldset class="equipment-selection">
|
||||||
<legend>{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.choice"}}</legend>
|
<legend>{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.choice"}}</legend>
|
||||||
|
|
||||||
<div class="simple-equipment-container">
|
<div class="simple-equipment-container">
|
||||||
{{#each inventory.choiceB.suggestions}}
|
{{#each inventory.choiceB.suggestions}}
|
||||||
<div class="simple-equipment selectable {{#if (not this.selected)}}inactive{{/if}}" data-action="equipmentChoice" data-path="choiceB" data-uuid="{{this.uuid}}" >
|
<div class="simple-equipment selectable {{#if (not this.selected)}}inactive{{/if}}" data-action="equipmentChoice" data-path="choiceB" data-uuid="{{this.uuid}}" >
|
||||||
<label>{{this.name}}</label>
|
<label>{{this.name}}</label>
|
||||||
<img src="{{this.img}}" />
|
<img src="{{this.img}}" />
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
{{/unless}}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<li class='feature-item' data-item-uuid='{{feature.uuid}}'>
|
<li class='feature-item' data-item-uuid='{{feature.uuid}}' data-type="{{type}}">
|
||||||
<div class='feature-line'>
|
<div class='feature-line'>
|
||||||
<img class='image' src='{{feature.img}}' />
|
<img class='image' src='{{feature.img}}' />
|
||||||
<h4>
|
<h4>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
data-tab='{{tabs.features.id}}'
|
data-tab='{{tabs.features.id}}'
|
||||||
data-group='{{tabs.features.group}}'
|
data-group='{{tabs.features.group}}'
|
||||||
>
|
>
|
||||||
<fieldset class="one-column drop-section primary-feature">
|
<fieldset class="one-column drop-section primary-feature" data-type="primary">
|
||||||
<legend>
|
<legend>
|
||||||
{{localize "DAGGERHEART.ITEMS.Ancestry.primaryFeature"}}
|
{{localize "DAGGERHEART.ITEMS.Ancestry.primaryFeature"}}
|
||||||
{{#unless document.system.primaryFeature}}<a><i data-action="addFeature" data-type="primary" class="fa-solid fa-plus icon-button"></i></a>{{/unless}}
|
{{#unless document.system.primaryFeature}}<a><i data-action="addFeature" data-type="primary" class="fa-solid fa-plus icon-button"></i></a>{{/unless}}
|
||||||
|
|
@ -11,20 +11,21 @@
|
||||||
<div class="features-list">
|
<div class="features-list">
|
||||||
{{#if document.system.primaryFeature}}
|
{{#if document.system.primaryFeature}}
|
||||||
<div class="feature-item"
|
<div class="feature-item"
|
||||||
data-action="editFeature"
|
data-action="editDoc"
|
||||||
|
data-item-uuid="{{document.system.primaryFeature.uuid}}"
|
||||||
data-type="primary"
|
data-type="primary"
|
||||||
>
|
>
|
||||||
<img class="image" src="{{document.system.primaryFeature.img}}" />
|
<img class="image" src="{{document.system.primaryFeature.img}}" />
|
||||||
<span>{{document.system.primaryFeature.name}}</span>
|
<span>{{document.system.primaryFeature.name}}</span>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<a data-action="removeFeature" data-type="primary"><i class="fa-solid fa-trash"></i></a>
|
<a data-action="deleteFeature"><i class="fa-solid fa-trash"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset class="one-column drop-section secondary-feature">
|
<fieldset class="one-column drop-section secondary-feature" data-type="secondary">
|
||||||
<legend>
|
<legend>
|
||||||
{{localize "DAGGERHEART.ITEMS.Ancestry.secondaryFeature"}}
|
{{localize "DAGGERHEART.ITEMS.Ancestry.secondaryFeature"}}
|
||||||
{{#unless document.system.secondaryFeature}}<a><i data-action="addFeature" data-type="secondary" class="fa-solid fa-plus icon-button"></i></a>{{/unless}}
|
{{#unless document.system.secondaryFeature}}<a><i data-action="addFeature" data-type="secondary" class="fa-solid fa-plus icon-button"></i></a>{{/unless}}
|
||||||
|
|
@ -32,13 +33,14 @@
|
||||||
<div class="features-list">
|
<div class="features-list">
|
||||||
{{#if document.system.secondaryFeature}}
|
{{#if document.system.secondaryFeature}}
|
||||||
<div class="feature-item"
|
<div class="feature-item"
|
||||||
data-action="editFeature"
|
data-action="editDoc"
|
||||||
|
data-item-uuid="{{document.system.secondaryFeature.uuid}}"
|
||||||
data-type="secondary"
|
data-type="secondary"
|
||||||
>
|
>
|
||||||
<img class="image" src="{{document.system.secondaryFeature.img}}" />
|
<img class="image" src="{{document.system.secondaryFeature.img}}" />
|
||||||
<span>{{document.system.secondaryFeature.name}}</span>
|
<span>{{document.system.secondaryFeature.name}}</span>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<a data-action="removeFeature" data-type="secondary"><i class="fa-solid fa-trash"></i></a>
|
<a data-action="deleteFeature"><i class="fa-solid fa-trash"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
data-group='{{tabs.features.group}}'
|
data-group='{{tabs.features.group}}'
|
||||||
>
|
>
|
||||||
<div class="two-columns even">
|
<div class="two-columns even">
|
||||||
<fieldset class="drop-section hope-feature">
|
<fieldset class="drop-section hope-feature" data-type='hope'>
|
||||||
<legend>{{localize "DAGGERHEART.ITEMS.Class.hopeFeatures"}} <a><i class="fa-solid fa-plus icon-button" data-type="hope" data-action="addFeature"></i></a></legend>
|
<legend>{{localize "DAGGERHEART.ITEMS.Class.hopeFeatures"}} <a><i class="fa-solid fa-plus icon-button" data-type="hope" data-action="addFeature"></i></a></legend>
|
||||||
<div class="feature-list">
|
<div class="feature-list">
|
||||||
{{#each source.system.hopeFeatures as |feature|}}
|
{{#each source.system.hopeFeatures as |feature|}}
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset class="drop-section class-feature">
|
<fieldset class="drop-section class-feature" data-type='class'>
|
||||||
<legend>{{localize "DAGGERHEART.ITEMS.Class.classFeatures"}} <a><i class="fa-solid fa-plus icon-button" data-type="class" data-action="addFeature"></i></a></legend>
|
<legend>{{localize "DAGGERHEART.ITEMS.Class.classFeatures"}} <a><i class="fa-solid fa-plus icon-button" data-type="class" data-action="addFeature"></i></a></legend>
|
||||||
<div class="feature-list">
|
<div class="feature-list">
|
||||||
{{#each source.system.classFeatures as |feature|}}
|
{{#each source.system.classFeatures as |feature|}}
|
||||||
|
|
@ -36,8 +36,8 @@
|
||||||
<div class='controls'>
|
<div class='controls'>
|
||||||
<a
|
<a
|
||||||
class='effect-control'
|
class='effect-control'
|
||||||
data-action='viewDoc'
|
data-action='editDoc'
|
||||||
data-uuid={{subclass.uuid}}
|
data-item-uuid={{subclass.uuid}}
|
||||||
data-tooltip='{{localize "DAGGERHEART.UI.Tooltip.openItemWorld"}}'
|
data-tooltip='{{localize "DAGGERHEART.UI.Tooltip.openItemWorld"}}'
|
||||||
>
|
>
|
||||||
<i class="fa-solid fa-globe"></i>
|
<i class="fa-solid fa-globe"></i>
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
<img class="image" src="{{document.system.characterGuide.suggestedPrimaryWeapon.img}}" />
|
<img class="image" src="{{document.system.characterGuide.suggestedPrimaryWeapon.img}}" />
|
||||||
<span>{{document.system.characterGuide.suggestedPrimaryWeapon.name}}</span>
|
<span>{{document.system.characterGuide.suggestedPrimaryWeapon.name}}</span>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<i data-action="removeSuggestedItem" data-target="suggestedPrimaryWeapon" class="fa-solid fa-trash icon-button"></i>
|
<a data-action="removeSuggestedItem" data-target="suggestedPrimaryWeapon"><i class="fa-solid fa-trash icon-button"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
@ -53,11 +53,11 @@
|
||||||
<legend>{{localize "DAGGERHEART.ITEMS.Class.guide.suggestedSecondaryWeaponTitle"}}</legend>
|
<legend>{{localize "DAGGERHEART.ITEMS.Class.guide.suggestedSecondaryWeaponTitle"}}</legend>
|
||||||
<div class="drop-section-body list-items">
|
<div class="drop-section-body list-items">
|
||||||
{{#if document.system.characterGuide.suggestedSecondaryWeapon}}
|
{{#if document.system.characterGuide.suggestedSecondaryWeapon}}
|
||||||
<div class="suggested-item item-line" data-action="editDoc" data-item-uuid="{{system.system.characterGuide.suggestedSecondaryWeapon.uuid}}">
|
<div class="suggested-item item-line" data-action="editDoc" data-item-uuid="{{document.system.characterGuide.suggestedSecondaryWeapon.uuid}}">
|
||||||
<img class="image" src="{{document.system.characterGuide.suggestedSecondaryWeapon.img}}" />
|
<img class="image" src="{{document.system.characterGuide.suggestedSecondaryWeapon.img}}" />
|
||||||
<span>{{document.system.characterGuide.suggestedSecondaryWeapon.name}}</span>
|
<span>{{document.system.characterGuide.suggestedSecondaryWeapon.name}}</span>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<i data-action="removeSuggestedItem" data-target="suggestedSecondaryWeapon" class="fa-solid fa-trash icon-button"></i>
|
<a data-action="removeSuggestedItem" data-target="suggestedSecondaryWeapon"><i class="fa-solid fa-trash icon-button"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
@ -72,7 +72,7 @@
|
||||||
<img class="image" src="{{document.system.characterGuide.suggestedArmor.img}}" />
|
<img class="image" src="{{document.system.characterGuide.suggestedArmor.img}}" />
|
||||||
<span>{{document.system.characterGuide.suggestedArmor.name}}</span>
|
<span>{{document.system.characterGuide.suggestedArmor.name}}</span>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<i data-action="removeSuggestedItem" data-target="suggestedArmor" class="fa-solid fa-trash icon-button"></i>
|
<a data-action="removeSuggestedItem" data-target="suggestedArmor"><i class="fa-solid fa-trash icon-button"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
@ -86,13 +86,15 @@
|
||||||
<legend>{{localize "DAGGERHEART.GENERAL.take"}}</legend>
|
<legend>{{localize "DAGGERHEART.GENERAL.take"}}</legend>
|
||||||
<div class="drop-section-body list-items">
|
<div class="drop-section-body list-items">
|
||||||
{{#each source.system.inventory.take}}
|
{{#each source.system.inventory.take}}
|
||||||
<div class="suggested-item item-line" data-action="editDoc" data-item-uuid="{{this.uuid}}">
|
{{#if this}}
|
||||||
<img class="image" src="{{this.img}}" />
|
<div class="suggested-item item-line" data-action="editDoc" data-item-uuid="{{this.uuid}}">
|
||||||
<span>{{this.name}}</span>
|
<img class="image" src="{{this.img}}" />
|
||||||
<div class="controls">
|
<span>{{this.name}}</span>
|
||||||
<i data-action="removeItemFromCollection" data-target="invetory.take" data-uuid="{{this.uuid}}" class="fa-solid fa-trash icon-button"></i>
|
<div class="controls">
|
||||||
|
<a data-action="removeItemFromCollection" data-target="inventory.take" data-uuid="{{this.uuid}}"><i class="fa-solid fa-trash icon-button"></i></a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{/if}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
@ -101,13 +103,15 @@
|
||||||
<legend>{{localize "DAGGERHEART.ITEMS.Class.guide.inventory.thenChoose"}}</legend>
|
<legend>{{localize "DAGGERHEART.ITEMS.Class.guide.inventory.thenChoose"}}</legend>
|
||||||
<div class="drop-section-body list-items">
|
<div class="drop-section-body list-items">
|
||||||
{{#each source.system.inventory.choiceA}}
|
{{#each source.system.inventory.choiceA}}
|
||||||
<div class="suggested-item item-line" data-action="editDoc" data-item-uuid="{{this.uuid}}">
|
{{#if this}}
|
||||||
<img class="image" src="{{this.img}}" />
|
<div class="suggested-item item-line" data-action="editDoc" data-item-uuid="{{this.uuid}}">
|
||||||
<span>{{this.name}}</span>
|
<img class="image" src="{{this.img}}" />
|
||||||
<div class="controls">
|
<span>{{this.name}}</span>
|
||||||
<i data-action="removeItemFromCollection" data-target="invetory.choiceA" data-uuid="{{this.uuid}}" class="fa-solid fa-trash icon-button"></i>
|
<div class="controls">
|
||||||
|
<a data-action="removeItemFromCollection" data-target="inventory.choiceA" data-uuid="{{this.uuid}}"><i class="fa-solid fa-trash icon-button"></i></a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{/if}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
@ -116,13 +120,15 @@
|
||||||
<legend>{{localize "DAGGERHEART.ITEMS.Class.guide.inventory.andEither"}}</legend>
|
<legend>{{localize "DAGGERHEART.ITEMS.Class.guide.inventory.andEither"}}</legend>
|
||||||
<div class="drop-section-body list-items">
|
<div class="drop-section-body list-items">
|
||||||
{{#each source.system.inventory.choiceB}}
|
{{#each source.system.inventory.choiceB}}
|
||||||
<div class="suggested-item item-line" data-action="editDoc" data-item-uuid="{{this.uuid}}">
|
{{#if this}}
|
||||||
<img class="image" src="{{this.img}}" />
|
<div class="suggested-item item-line" data-action="editDoc" data-item-uuid="{{this.uuid}}">
|
||||||
<span>{{this.name}}</span>
|
<img class="image" src="{{this.img}}" />
|
||||||
<div class="controls">
|
<span>{{this.name}}</span>
|
||||||
<i data-action="removeItemFromCollection" data-target="invetory.choiceB" data-uuid="{{this.uuid}}" class="fa-solid fa-trash icon-button"></i>
|
<div class="controls">
|
||||||
|
<a data-action="removeItemFromCollection" data-target="inventory.choiceB" data-uuid="{{this.uuid}}"><i class="fa-solid fa-trash icon-button"></i></a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{/if}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
<fieldset class="two-columns">
|
<fieldset class="two-columns">
|
||||||
{{#with systemFields.attack.fields.damage.fields.parts.element.fields as | fields | }}
|
{{#with systemFields.attack.fields.damage.fields.parts.element.fields as | fields | }}
|
||||||
{{#with (lookup ../document.system.attack.damage.parts 0) as | source | }}
|
{{#with (lookup ../document.system.attack.damage.parts 0) as | source | }}
|
||||||
<legend>{{localize "DAGGERHEART.GENERAL.title"}}</legend>
|
<legend>{{localize "DAGGERHEART.GENERAL.damage"}}</legend>
|
||||||
<span>{{localize "DAGGERHEART.GENERAL.Dice.single"}}</span>
|
<span>{{localize "DAGGERHEART.GENERAL.Dice.single"}}</span>
|
||||||
{{formInput fields.value.fields.dice value=source.value.dice name="system.attack.damage.parts.0.value.dice"}}
|
{{formInput fields.value.fields.dice value=source.value.dice name="system.attack.damage.parts.0.value.dice"}}
|
||||||
<span>{{localize "DAGGERHEART.GENERAL.bonus"}}</span>
|
<span>{{localize "DAGGERHEART.GENERAL.bonus"}}</span>
|
||||||
|
|
|
||||||
|
|
@ -33,5 +33,5 @@
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.customActions label=(localize "DAGGERHEART.GENERAL.Action.plural")}}
|
{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.customActions isAction=true label=(localize "DAGGERHEART.GENERAL.Action.plural")}}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -10,5 +10,5 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.actions label=(localize "DAGGERHEART.GENERAL.Action.plural") }}
|
{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.actions isAction=true label=(localize "DAGGERHEART.GENERAL.Action.plural") }}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -27,5 +27,5 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.actions label=(localize "DAGGERHEART.GENERAL.Action.plural") }}
|
{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.actions isAction=true label=(localize "DAGGERHEART.GENERAL.Action.plural") }}
|
||||||
</div>
|
</div>
|
||||||
5
templates/ui/tooltip/effect.hbs
Normal file
5
templates/ui/tooltip/effect.hbs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<div class="daggerheart dh-style tooltip">
|
||||||
|
<h2 class="tooltip-title">{{item.name}}</h2>
|
||||||
|
<img class="tooltip-image" src="{{item.img}}" />
|
||||||
|
<div class="tooltip-description">{{{description}}}</div>
|
||||||
|
</div>
|
||||||
|
|
@ -3,6 +3,6 @@
|
||||||
<img class="tooltip-image" src="{{item.img}}" />
|
<img class="tooltip-image" src="{{item.img}}" />
|
||||||
<div class="tooltip-description">{{{description}}}</div>
|
<div class="tooltip-description">{{{description}}}</div>
|
||||||
|
|
||||||
{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.actions label=(localize "DAGGERHEART.GENERAL.Action.plural") }}
|
{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.actions isAction=true label=(localize "DAGGERHEART.GENERAL.Action.plural") }}
|
||||||
{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.effects label=(localize "DAGGERHEART.GENERAL.Effect.plural") }}
|
{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.effects label=(localize "DAGGERHEART.GENERAL.Effect.plural") }}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -3,5 +3,5 @@
|
||||||
<img class="tooltip-image" src="{{item.img}}" />
|
<img class="tooltip-image" src="{{item.img}}" />
|
||||||
<div class="tooltip-description">{{{description}}}</div>
|
<div class="tooltip-description">{{{description}}}</div>
|
||||||
|
|
||||||
{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.actions label=(localize "DAGGERHEART.GENERAL.Action.plural") }}
|
{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.actions isAction=true label=(localize "DAGGERHEART.GENERAL.Action.plural") }}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
{{#if (gt features.length 0)}}<h4 class="tooltip-sub-title">{{label}}</h4>{{/if}}
|
{{#if (gt features.length 0)}}<h4 class="tooltip-sub-title">{{label}}</h4>{{/if}}
|
||||||
<div class="tooltip-tags">
|
<div class="tooltip-tags">
|
||||||
{{#each features as | feature |}}
|
{{#each features as | feature |}}
|
||||||
<div class="tooltip-tag">
|
{{#with (ifThen ../isAction feature (ifThen feature.item feature.item feature))}}
|
||||||
<div class="tooltip-tag-label-container">
|
<div class="tooltip-tag">
|
||||||
<div class="tooltip-tag-label">{{localize feature.name}}</div>
|
<div class="tooltip-tag-label-container">
|
||||||
{{#if feature.img}}<img class="tooltip-tag-image" src="{{feature.img}}" />{{/if}}
|
<div class="tooltip-tag-label">{{localize this.name}}</div>
|
||||||
</div>
|
{{#if this.img}}<img class="tooltip-tag-image" src="{{this.img}}" />{{/if}}
|
||||||
<div class="tooltip-tag-description">{{{localize (ifThen feature.description feature.description (ifThen feature.system.enrichedDescription feature.system.enrichedDescription feature.system.description))}}}</div>
|
</div>
|
||||||
</div>
|
<div class="tooltip-tag-description">{{{localize (ifThen this.enrichedDescription this.enrichedDescription this.system.enrichedDescription)}}}</div>
|
||||||
|
</div>
|
||||||
|
{{/with}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -52,5 +52,5 @@
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.customActions label=(localize "DAGGERHEART.GENERAL.Action.plural") }}
|
{{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.customActions isAction=true label=(localize "DAGGERHEART.GENERAL.Action.plural") }}
|
||||||
</div>
|
</div>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue