diff --git a/lang/en.json b/lang/en.json index 5c0c7470..7b8b45c7 100755 --- a/lang/en.json +++ b/lang/en.json @@ -213,6 +213,9 @@ "headerTitle": "Adversary Reaction Roll" } }, + "Base": { + "CannotAddType": "Cannot add {itemType} items to {actorType} actors." + }, "Character": { "advantageSources": { "label": "Advantage Sources", @@ -2878,6 +2881,10 @@ } }, "Keybindings": { + "partySheet": { + "name": "Toggle Party Sheet", + "hint": "Open or close the active party's sheet" + }, "spotlight": { "name": "Spotlight Combatant", "hint": "Move the spotlight to a hovered or selected token that's present in an active encounter" diff --git a/module/applications/dialogs/d20RollDialog.mjs b/module/applications/dialogs/d20RollDialog.mjs index 64fa168a..067aa473 100644 --- a/module/applications/dialogs/d20RollDialog.mjs +++ b/module/applications/dialogs/d20RollDialog.mjs @@ -123,6 +123,10 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio context.advantage = this.config.roll?.advantage; context.disadvantage = this.config.roll?.disadvantage; context.diceOptions = CONFIG.DH.GENERAL.diceTypes; + context.dieFaces = CONFIG.DH.GENERAL.dieFaces.reduce((acc, face) => { + acc[face] = `d${face}`; + return acc; + }, {}); context.isLite = this.config.roll?.lite; context.extraFormula = this.config.extraFormula; context.formula = this.roll.constructFormula(this.config); @@ -152,9 +156,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio } if (this.config.uses) this.config.uses = foundry.utils.mergeObject(this.config.uses, rest.uses); if (rest.roll?.dice) { - Object.entries(rest.roll.dice).forEach(([key, value]) => { - this.roll[key] = value; - }); + this.roll = foundry.utils.mergeObject(this.roll, rest.roll.dice); } if (rest.hasOwnProperty('trait')) { this.config.roll.trait = rest.trait; @@ -173,6 +175,15 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio this.disadvantage = advantage === -1; this.config.roll.advantage = this.config.roll.advantage === advantage ? 0 : advantage; + + if (this.config.roll.advantage === 1 && this.config.data.rules.roll.defaultAdvantageDice) { + const faces = Number.parseInt(this.config.data.rules.roll.defaultAdvantageDice); + this.roll.advantageFaces = Number.isNaN(faces) ? this.roll.advantageFaces : faces; + } else if (this.config.roll.advantage === -1 && this.config.data.rules.roll.defaultDisadvantageDice) { + const faces = Number.parseInt(this.config.data.rules.roll.defaultDisadvantageDice); + this.roll.advantageFaces = Number.isNaN(faces) ? this.roll.advantageFaces : faces; + } + this.render(); } diff --git a/module/applications/dialogs/itemTransfer.mjs b/module/applications/dialogs/itemTransfer.mjs index ad3cf103..42e3a727 100644 --- a/module/applications/dialogs/itemTransfer.mjs +++ b/module/applications/dialogs/itemTransfer.mjs @@ -38,13 +38,15 @@ export default class ItemTransferDialog extends HandlebarsApplicationMixin(Appli originActor ??= item?.actor; const homebrewKey = CONFIG.DH.SETTINGS.gameSettings.Homebrew; const currencySetting = game.settings.get(CONFIG.DH.id, homebrewKey).currency?.[currency] ?? null; + const max = item?.system.quantity ?? originActor.system.gold[currency] ?? 0; return { originActor, targetActor, itemImage: item?.img, currencyIcon: currencySetting?.icon, - max: item?.system.quantity ?? originActor.system.gold[currency] ?? 0, + max, + initial: targetActor.system.metadata.quantifiable?.includes(item.type) ? max : 1, title: item?.name ?? currencySetting?.label }; } diff --git a/module/applications/sheets/api/base-actor.mjs b/module/applications/sheets/api/base-actor.mjs index 4a550d72..e23a4426 100644 --- a/module/applications/sheets/api/base-actor.mjs +++ b/module/applications/sheets/api/base-actor.mjs @@ -73,7 +73,7 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) { .hideAttribution; // Prepare inventory data - if (['party', 'character'].includes(this.document.type)) { + if (this.document.system.metadata.hasInventory) { context.inventory = { currencies: {}, weapons: this.document.itemTypes.weapon.sort((a, b) => a.sort - b.sort), @@ -283,11 +283,7 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) { async _onDropItem(event, item) { const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); const originActor = item.actor; - if ( - item.actor?.uuid === this.document.uuid || - !originActor || - !['character', 'party'].includes(this.document.type) - ) { + if (!originActor || originActor.uuid === this.document.uuid || !this.document.system.metadata.hasInventory) { return super._onDropItem(event, item); } @@ -302,47 +298,79 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) { ); } - if (item.system.metadata.isQuantifiable) { - const actorItem = originActor.items.get(data.originId); - const quantityTransfered = await game.system.api.applications.dialogs.ItemTransferDialog.configure({ + // Perform the actual transfer, showing a dialog when doing it + const availableQuantity = Math.max(1, item.system.quantity); + const actorItem = originActor.items.get(data.originId) ?? item; + if (availableQuantity > 1) { + const quantityTransferred = await game.system.api.applications.dialogs.ItemTransferDialog.configure({ item, targetActor: this.document }); - - if (quantityTransfered) { - const existingItem = this.document.items.find(x => itemIsIdentical(x, item)); - if (existingItem) { - await existingItem.update({ - 'system.quantity': existingItem.system.quantity + quantityTransfered - }); - } else { - const createData = item.toObject(); - await this.document.createEmbeddedDocuments('Item', [ - { - ...createData, - system: { - ...createData.system, - quantity: quantityTransfered - } - } - ]); - } - - if (quantityTransfered === actorItem.system.quantity) { - await originActor.deleteEmbeddedDocuments('Item', [data.originId]); - } else { - await actorItem.update({ - 'system.quantity': actorItem.system.quantity - quantityTransfered - }); - } - } + return this.#transferItem(actorItem, quantityTransferred); } else { - await this.document.createEmbeddedDocuments('Item', [item.toObject()]); - await originActor.deleteEmbeddedDocuments('Item', [data.originId]); + return this.#transferItem(actorItem, availableQuantity); } } } + /** + * Helper to perform the actual transfer of an item to this actor, including stack/unstack logic based on target quantifiability. + * Make sure item is the actor item before calling this method or there will be issues + */ + async #transferItem(item, quantity) { + const originActor = item.actor; + const targetActor = this.document; + const allowStacking = targetActor.system.metadata.quantifiable?.includes(item.type); + + const batch = []; + + // First add/update the item to the target actor + const existing = allowStacking ? targetActor.items.find(x => itemIsIdentical(x, item)) : null; + if (existing) { + batch.push({ + action: 'update', + documentName: 'Item', + parent: targetActor, + updates: [{ '_id': existing.id, 'system.quantity': existing.system.quantity + quantity }] + }); + } else { + const itemsToCreate = []; + if (allowStacking) { + itemsToCreate.push(foundry.utils.mergeObject(item.toObject(true), { system: { quantity } })); + } else { + const createData = new Array(Math.max(1, quantity)) + .fill(0) + .map(() => foundry.utils.mergeObject(item.toObject(), { system: { quantity: 1 } })); + itemsToCreate.push(...createData); + } + batch.push({ + action: 'create', + documentName: 'Item', + parent: targetActor, + data: itemsToCreate + }); + } + + // Remove the item from the original actor (by either deleting it, or updating its quantity) + if (quantity >= item.system.quantity) { + batch.push({ + action: 'delete', + documentName: 'Item', + parent: originActor, + ids: [item.id] + }); + } else { + batch.push({ + action: 'update', + documentName: 'Item', + parent: originActor, + updates: [{ '_id': item.id, 'system.quantity': item.system.quantity - quantity }] + }); + } + + return foundry.documents.modifyBatch(batch); + } + /** * On dragStart on the item. * @param {DragEvent} event - The drag event diff --git a/module/applications/sheets/items/ancestry.mjs b/module/applications/sheets/items/ancestry.mjs index 8c0a5620..cf040e02 100644 --- a/module/applications/sheets/items/ancestry.mjs +++ b/module/applications/sheets/items/ancestry.mjs @@ -31,11 +31,12 @@ export default class AncestrySheet extends DHHeritageSheet { if (data.type === 'ActiveEffect') return super._onDrop(event); const target = event.target.closest('fieldset.drop-section'); - const typeField = - this.document.system[target.dataset.type === 'primary' ? 'primaryFeature' : 'secondaryFeature']; - - if (!typeField) { - super._onDrop(event); + if (target) { + const typeField = + this.document.system[target.dataset.type === 'primary' ? 'primaryFeature' : 'secondaryFeature']; + if (!typeField) { + super._onDrop(event); + } } } } diff --git a/module/config/settingsConfig.mjs b/module/config/settingsConfig.mjs index 12e8536e..6dae29aa 100644 --- a/module/config/settingsConfig.mjs +++ b/module/config/settingsConfig.mjs @@ -1,5 +1,6 @@ export const keybindings = { - spotlight: 'DHSpotlight' + spotlight: 'DHSpotlight', + partySheet: 'DHPartySheet' }; export const menu = { diff --git a/module/data/actor/adversary.mjs b/module/data/actor/adversary.mjs index 73673896..d30e090a 100644 --- a/module/data/actor/adversary.mjs +++ b/module/data/actor/adversary.mjs @@ -133,7 +133,7 @@ export default class DhpAdversary extends DhCreature { } isItemValid(source) { - return source.type === 'feature'; + return super.isItemValid(source) || source.type === 'feature'; } async _preUpdate(changes, options, user) { diff --git a/module/data/actor/base.mjs b/module/data/actor/base.mjs index 89ba5db2..13ff0a38 100644 --- a/module/data/actor/base.mjs +++ b/module/data/actor/base.mjs @@ -107,7 +107,8 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel { hasResistances: true, hasAttribution: false, hasLimitedView: true, - usesSize: false + usesSize: false, + hasInventory: false }; } @@ -168,6 +169,11 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel { /* -------------------------------------------- */ + isItemValid(source) { + const inventoryTypes = ['weapon', 'armor', 'consumable', 'loot']; + return this.metadata.hasInventory && inventoryTypes.includes(source.type); + } + /** * Obtain a data object used to evaluate any dice rolls associated with this Item Type * @param {object} [options] - Options which modify the getRollData method. diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 0e1e2259..bf3d7bb8 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -18,7 +18,9 @@ export default class DhCharacter extends DhCreature { label: 'TYPES.Actor.character', type: 'character', settingSheet: DHCharacterSettings, - isNPC: false + isNPC: false, + hasInventory: true, + quantifiable: ["loot", "consumable"] }); } @@ -284,7 +286,23 @@ export default class DhCharacter extends DhCreature { guaranteedCritical: new fields.BooleanField({ label: 'DAGGERHEART.ACTORS.Character.roll.guaranteedCritical.label', hint: 'DAGGERHEART.ACTORS.Character.roll.guaranteedCritical.hint' - }) + }), + defaultAdvantageDice: new fields.NumberField({ + nullable: true, + required: true, + integer: true, + choices: CONFIG.DH.GENERAL.dieFaces, + initial: null, + label: 'DAGGERHEART.ACTORS.Character.defaultAdvantageDice' + }), + defaultDisadvantageDice: new fields.NumberField({ + nullable: true, + required: true, + integer: true, + choices: CONFIG.DH.GENERAL.dieFaces, + initial: null, + label: 'DAGGERHEART.ACTORS.Character.defaultDisadvantageDice' + }), }) }) }; @@ -429,6 +447,11 @@ export default class DhCharacter extends DhCreature { return attack; } + /* All items are valid on characters */ + isItemValid() { + return true; + } + /** @inheritDoc */ isItemAvailable(item) { if (!super.isItemAvailable(this)) return false; diff --git a/module/data/actor/companion.mjs b/module/data/actor/companion.mjs index 81d0aa8a..a1fa1429 100644 --- a/module/data/actor/companion.mjs +++ b/module/data/actor/companion.mjs @@ -61,6 +61,24 @@ export default class DhCompanion extends DhCreature { initial: false, label: 'DAGGERHEART.GENERAL.Rules.conditionImmunities.vulnerable' }) + }), + roll: new fields.SchemaField({ + defaultAdvantageDice: new fields.NumberField({ + nullable: true, + required: true, + integer: true, + choices: CONFIG.DH.GENERAL.dieFaces, + initial: null, + label: 'DAGGERHEART.ACTORS.Character.defaultAdvantageDice' + }), + defaultDisadvantageDice: new fields.NumberField({ + nullable: true, + required: true, + integer: true, + choices: CONFIG.DH.GENERAL.dieFaces, + initial: null, + label: 'DAGGERHEART.ACTORS.Character.defaultDisadvantageDice' + }), }) }), attack: new ActionField({ @@ -118,10 +136,6 @@ export default class DhCompanion extends DhCreature { return this.levelupChoicesLeft > 0; } - isItemValid() { - return false; - } - prepareBaseData() { super.prepareBaseData(); this.attack.roll.bonus = this.partner?.system?.spellcastModifier ?? 0; diff --git a/module/data/actor/environment.mjs b/module/data/actor/environment.mjs index e06f038c..e037e004 100644 --- a/module/data/actor/environment.mjs +++ b/module/data/actor/environment.mjs @@ -56,7 +56,7 @@ export default class DhEnvironment extends BaseDataActor { } isItemValid(source) { - return source.type === 'feature'; + return super.isItemValid(source) || source.type === 'feature'; } _onUpdate(changes, options, userId) { diff --git a/module/data/actor/party.mjs b/module/data/actor/party.mjs index ea09c622..6ccf8852 100644 --- a/module/data/actor/party.mjs +++ b/module/data/actor/party.mjs @@ -5,6 +5,14 @@ import GroupRollData from '../groupRollData.mjs'; import { GoldField } from '../fields/actorField.mjs'; export default class DhParty extends BaseDataActor { + /** @inheritdoc */ + static get metadata() { + return foundry.utils.mergeObject(super.metadata, { + hasInventory: true, + quantifiable: ["weapon", "armor", "loot", "consumable"] + }); + } + /**@inheritdoc */ static defineSchema() { const fields = foundry.data.fields; @@ -29,10 +37,6 @@ export default class DhParty extends BaseDataActor { /* -------------------------------------------- */ - isItemValid(source) { - return ['weapon', 'armor', 'consumable', 'loot'].includes(source.type); - } - prepareBaseData() { super.prepareBaseData(); diff --git a/module/data/item/base.mjs b/module/data/item/base.mjs index 21a11149..72718c5e 100644 --- a/module/data/item/base.mjs +++ b/module/data/item/base.mjs @@ -4,7 +4,6 @@ * @property {string} label - A localizable label used on application. * @property {string} type - The system type that this data model represents. * @property {boolean} hasDescription - Indicates whether items of this type have description field - * @property {boolean} isQuantifiable - Indicates whether items of this type have quantity field * @property {boolean} isInventoryItem- Indicates whether items of this type is a Inventory Item */ @@ -24,7 +23,6 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { type: 'base', hasDescription: false, hasResource: false, - isQuantifiable: false, isInventoryItem: false, hasActions: false, hasAttribution: true @@ -83,7 +81,7 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { ); } - if (this.metadata.isQuantifiable) + if (this.metadata.isInventoryItem) schema.quantity = new fields.NumberField({ integer: true, initial: 1, min: 0, required: true }); if (this.metadata.hasActions) schema.actions = new ActionsField(); diff --git a/module/data/item/consumable.mjs b/module/data/item/consumable.mjs index ab527967..e83a1a53 100644 --- a/module/data/item/consumable.mjs +++ b/module/data/item/consumable.mjs @@ -7,7 +7,6 @@ export default class DHConsumable extends BaseDataItem { label: 'TYPES.Item.consumable', type: 'consumable', hasDescription: true, - isQuantifiable: true, isInventoryItem: true, hasActions: true }); diff --git a/module/data/item/loot.mjs b/module/data/item/loot.mjs index cdb0855e..d4092934 100644 --- a/module/data/item/loot.mjs +++ b/module/data/item/loot.mjs @@ -7,7 +7,6 @@ export default class DHLoot extends BaseDataItem { label: 'TYPES.Item.loot', type: 'loot', hasDescription: true, - isQuantifiable: true, isInventoryItem: true, hasActions: true }); diff --git a/module/dice/dualityRoll.mjs b/module/dice/dualityRoll.mjs index f9a06d37..2448a16d 100644 --- a/module/dice/dualityRoll.mjs +++ b/module/dice/dualityRoll.mjs @@ -3,7 +3,6 @@ import D20Roll from './d20Roll.mjs'; import { parseRallyDice, setDiceSoNiceForDualityRoll } from '../helpers/utils.mjs'; export default class DualityRoll extends D20Roll { - _advantageFaces = 6; _advantageNumber = 1; _rallyIndex; @@ -11,6 +10,9 @@ export default class DualityRoll extends D20Roll { super(formula, data, options); this.rallyChoices = this.setRallyChoices(); this.guaranteedCritical = options.guaranteedCritical; + + const advantageFaces = data.rules?.roll?.defaultAdvantageDice ? Number.parseInt(data.rules.roll.defaultAdvantageDice) : 6 + this.advantageFaces = Number.isNaN(advantageFaces) ? 6 : advantageFaces; } static messageType = 'dualityRoll'; @@ -51,14 +53,6 @@ export default class DualityRoll extends D20Roll { return this.dice[2] instanceof game.system.api.dice.diceTypes.DisadvantageDie ? this.dice[2] : null; } - get advantageFaces() { - return this._advantageFaces; - } - - set advantageFaces(faces) { - this._advantageFaces = this.getFaces(faces); - } - get advantageNumber() { return this._advantageNumber; } diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 8ae2e062..4e20db0e 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -113,7 +113,7 @@ export default class DhpActor extends Actor { _onUpdate(changes, options, userId) { super._onUpdate(changes, options, userId); for (const party of this.parties) { - party.render(); + party.render({ parts: ['partyMembers'] }); } } @@ -132,7 +132,7 @@ export default class DhpActor extends Actor { _onDelete(options, userId) { super._onDelete(options, userId); for (const party of this.parties) { - party.render(); + party.render({ parts: ['partyMembers'] }); } } diff --git a/module/documents/item.mjs b/module/documents/item.mjs index d1a618c7..a8b41b05 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -31,8 +31,13 @@ export default class DHItem extends foundry.documents.Item { static async createDocuments(sources, operation) { // Ensure that items being created are valid to the actor its being added to const actor = operation.parent; - sources = actor?.system?.isItemValid ? sources.filter(s => actor.system.isItemValid(s)) : sources; - return super.createDocuments(sources, operation); + const filtered = actor ? sources.filter(s => actor.system.isItemValid(s)) : sources; + if (actor && filtered.length === 0 && sources.length > 0) { + const itemType = _loc(`TYPES.Item.${sources[0].type}`); + const actorType = _loc(`TYPES.Actor.${actor.type}`); + ui.notifications.error('DAGGERHEART.ACTORS.Base.CannotAddType', { format: { itemType, actorType } }); + } + return super.createDocuments(filtered, operation); } /* -------------------------------------------- */ diff --git a/module/systemRegistration/settings.mjs b/module/systemRegistration/settings.mjs index ae78e23b..69bd1730 100644 --- a/module/systemRegistration/settings.mjs +++ b/module/systemRegistration/settings.mjs @@ -52,6 +52,27 @@ export const registerKeyBindings = () => { reservedModifiers: [], precedence: CONST.KEYBINDING_PRECEDENCE.NORMAL }); + + game.keybindings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.keybindings.partySheet, { + name: _loc('DAGGERHEART.SETTINGS.Keybindings.partySheet.name'), + hint: _loc('DAGGERHEART.SETTINGS.Keybindings.partySheet.hint'), + editable: [{ key: "KeyP" }], + onDown: () => { + const controlled = canvas.ready ? canvas.tokens.controlled : []; + const selectedParty = controlled.find((c) => c.actor?.type === 'party')?.actor; + const party = selectedParty ?? game.actors.party; + if (!party) return; + + const sheet = party.sheet; + if (!sheet.rendered) { + sheet.render(true); + } else if (sheet.minimized) { + sheet.maximize(); + } else { + sheet.close(); + } + } + }); }; const registerMenuSettings = () => { diff --git a/templates/dialogs/dice-roll/rollSelection.hbs b/templates/dialogs/dice-roll/rollSelection.hbs index 2deccaf2..2c1a21b6 100644 --- a/templates/dialogs/dice-roll/rollSelection.hbs +++ b/templates/dialogs/dice-roll/rollSelection.hbs @@ -157,8 +157,8 @@ {{/times}} - + {{selectOptions dieFaces selected=@root.roll.advantageFaces}} {{#if abilities}} diff --git a/templates/dialogs/item-transfer.hbs b/templates/dialogs/item-transfer.hbs index 0e7df3dc..63972ed8 100644 --- a/templates/dialogs/item-transfer.hbs +++ b/templates/dialogs/item-transfer.hbs @@ -14,7 +14,7 @@
- +
diff --git a/templates/sheets/actors/character/inventory.hbs b/templates/sheets/actors/character/inventory.hbs index aad1cf7e..30812e17 100644 --- a/templates/sheets/actors/character/inventory.hbs +++ b/templates/sheets/actors/character/inventory.hbs @@ -39,6 +39,7 @@ collection=@root.inventory.consumables isGlassy=true canCreate=true + isQuantifiable=true }} {{> 'daggerheart.inventory-items' title='TYPES.Item.loot' @@ -47,6 +48,7 @@ isGlassy=true canCreate=true showActions=true + isQuantifiable=true }} \ No newline at end of file diff --git a/templates/sheets/actors/party/inventory.hbs b/templates/sheets/actors/party/inventory.hbs index 8dd10154..74492c73 100644 --- a/templates/sheets/actors/party/inventory.hbs +++ b/templates/sheets/actors/party/inventory.hbs @@ -29,6 +29,7 @@ canCreate=true hideResources=true hideContextMenu=true + isQuantifiable=true }} {{> 'daggerheart.inventory-items' title='TYPES.Item.armor' @@ -39,6 +40,7 @@ canCreate=true hideResources=true hideContextMenu=true + isQuantifiable=true }} {{> 'daggerheart.inventory-items' title='TYPES.Item.consumable' @@ -48,6 +50,7 @@ isGlassy=true canCreate=true hideContextMenu=true + isQuantifiable=true }} {{> 'daggerheart.inventory-items' title='TYPES.Item.loot' @@ -57,6 +60,7 @@ isGlassy=true canCreate=true hideContextMenu=true + isQuantifiable=true }} \ No newline at end of file diff --git a/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs b/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs index 31c8f7f5..5c6eae32 100644 --- a/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs +++ b/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs @@ -66,6 +66,7 @@ Parameters: showLabels=../showLabels isAction=../isAction hideResources=../hideResources + isQuantifiable=../isQuantifiable showActions=../showActions }} diff --git a/templates/sheets/global/partials/inventory-item-V2.hbs b/templates/sheets/global/partials/inventory-item-V2.hbs index 2129b969..25f1715c 100644 --- a/templates/sheets/global/partials/inventory-item-V2.hbs +++ b/templates/sheets/global/partials/inventory-item-V2.hbs @@ -63,10 +63,10 @@ Parameters: {{#if (and (not hideResources) (not (eq item.system.resource.type 'diceValue')))}} {{> "systems/daggerheart/templates/sheets/global/partials/item-resource.hbs"}} {{/if}} - {{#if (and (not hideResources) (gte item.system.quantity 0))}} -
- -
+ {{#if (or isQuantifiable (or (eq item.system.quantity 0) (gt item.system.quantity 1)))}} +
+ +
{{/if}} {{!-- Controls --}}