FEAT: add resources to inventory-item template

This commit is contained in:
Joaquin Pereyra 2025-07-16 13:41:22 -03:00
parent d26ed22e74
commit aee8753f63
19 changed files with 224 additions and 222 deletions

View file

@ -23,11 +23,8 @@ export default class CharacterSheet extends DHBaseActorSheet {
makeDeathMove: CharacterSheet.#makeDeathMove, makeDeathMove: CharacterSheet.#makeDeathMove,
levelManagement: CharacterSheet.#levelManagement, levelManagement: CharacterSheet.#levelManagement,
toggleEquipItem: CharacterSheet.#toggleEquipItem, toggleEquipItem: CharacterSheet.#toggleEquipItem,
useItem: this.useItem, //TODO Fix this toggleResourceDice: CharacterSheet.#toggleResourceDice,
useAction: this.useAction, handleResourceDice: CharacterSheet.#handleResourceDice,
toggleResourceDice: this.toggleResourceDice,
handleResourceDice: this.handleResourceDice,
toChat: this.toChat
}, },
window: { window: {
resizable: true resizable: true
@ -505,22 +502,21 @@ export default class CharacterSheet extends DHBaseActorSheet {
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Application Listener Actions */ /* Application Listener Actions */
/* -------------------------------------------- */ /* -------------------------------------------- */
async updateItemResource(event) { async updateItemResource(event) {
const item = this.getItem(event.currentTarget); const item = getDocFromElement(event.currentTarget);
if (!item) return; if (!item) return;
const max = item.system.resource.max ? itemAbleRollParse(item.system.resource.max, this.document, item) : null; const max = item.system.resource.max ? itemAbleRollParse(item.system.resource.max, this.document, item) : null;
const value = max ? Math.min(Number(event.currentTarget.value), max) : event.currentTarget.value; const value = max ? Math.min(Number(event.currentTarget.value), max) : event.currentTarget.value;
await item.update({ 'system.resource.value': value }); await item.update({ 'system.resource.value': value });
this.render();
} }
async updateItemQuantity(event) { async updateItemQuantity(event) {
const item = this.getItem(event.currentTarget); const item = getDocFromElement(event.currentTarget);
if (!item) return; if (!item) return;
await item.update({ 'system.quantity': event.currentTarget.value }); await item.update({ 'system.quantity': event.currentTarget.value });
this.render();
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -641,53 +637,18 @@ export default class CharacterSheet extends DHBaseActorSheet {
await doc?.update({ 'system.inVault': !doc.system.inVault }); await doc?.update({ 'system.inVault': !doc.system.inVault });
} }
/**
* Use a item
* @type {ApplicationClickAction}
*/
static async useItem(event, button) {
const item = this.getItem(button);
if (!item) return;
// Should dandle its actions. Or maybe they'll be separate buttons as per an Issue on the board
if (item.type === 'feature') {
item.use(event);
} else if (item instanceof ActiveEffect) {
item.toChat(this);
} else {
const wasUsed = await item.use(event);
if (wasUsed && item.type === 'weapon') {
Hooks.callAll(CONFIG.DH.HOOKS.characterAttack, {});
}
}
}
/**
* Use an action
* @type {ApplicationClickAction}
*/
static async useAction(event, button) {
const item = this.getItem(button);
if (!item) return;
const action = item.system.actions.find(x => x.id === button.dataset.actionId);
if (!action) return;
action.use(event);
}
/** /**
* Toggle the used state of a resource dice. * Toggle the used state of a resource dice.
* @type {ApplicationClickAction} * @type {ApplicationClickAction}
*/ */
static async toggleResourceDice(event) { static async #toggleResourceDice(event, target) {
const target = event.target.closest('.item-resource'); const item = getDocFromElement(target);
const item = this.getItem(event);
if (!item) return; const { dice } = event.target.closest('.item-resource').dataset;
const diceState = item.system.resource.diceStates[dice];
const diceState = item.system.resource.diceStates[target.dataset.dice];
await item.update({ await item.update({
[`system.resource.diceStates.${target.dataset.dice}.used`]: diceState?.used ? !diceState.used : true [`system.resource.diceStates.${dice}.used`]: !diceState.used
}); });
} }
@ -695,8 +656,8 @@ export default class CharacterSheet extends DHBaseActorSheet {
* Handle the roll values of resource dice. * Handle the roll values of resource dice.
* @type {ApplicationClickAction} * @type {ApplicationClickAction}
*/ */
static async handleResourceDice(event) { static async #handleResourceDice(_, target) {
const item = this.getItem(event); const item = getDocFromElement(target);
if (!item) return; if (!item) return;
const rollValues = await game.system.api.applications.dialogs.ResourceDiceDialog.create(item, this.document); const rollValues = await game.system.api.applications.dialogs.ResourceDiceDialog.create(item, this.document);
@ -708,41 +669,11 @@ export default class CharacterSheet extends DHBaseActorSheet {
return acc; return acc;
}, {}) }, {})
}); });
this.render(); //this.render();
}
/**
* Send item to Chat
* @type {ApplicationClickAction}
*/
static async toChat(event, button) {
if (button?.dataset?.type === 'experience') {
const experience = this.document.system.experiences[button.dataset.uuid];
const cls = getDocumentClass('ChatMessage');
const systemData = {
name: game.i18n.localize('DAGGERHEART.GENERAL.Experience.single'),
description: `${experience.name} ${experience.value.signedString()}`
};
const msg = new cls({
type: 'abilityUse',
user: game.user.id,
system: systemData,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/ui/chat/ability-use.hbs',
systemData
)
});
cls.create(msg.toObject());
} else {
const item = this.getItem(event);
if (!item) return;
item.toChat(this.document.id);
}
} }
async _onDragStart(event) { async _onDragStart(event) {
const item = this.getItem(event); const item = getDocFromElement(event.target);
const dragData = { const dragData = {
type: item.documentName, type: item.documentName,

View file

@ -82,6 +82,7 @@ export default function DHApplicationMixin(Base) {
deleteDoc: DHSheetV2.#deleteDoc, deleteDoc: DHSheetV2.#deleteDoc,
toChat: DHSheetV2.#toChat, toChat: DHSheetV2.#toChat,
useItem: DHSheetV2.#useItem, useItem: DHSheetV2.#useItem,
useAction: DHSheetV2.#useAction,
toggleEffect: DHSheetV2.#toggleEffect, toggleEffect: DHSheetV2.#toggleEffect,
}, },
contextMenus: [{ contextMenus: [{
@ -485,17 +486,29 @@ export default function DHApplicationMixin(Base) {
*/ */
static async #useItem(event, target) { static async #useItem(event, target) {
let doc = getDocFromElement(target); let doc = getDocFromElement(target);
// TODO: REDO this // TODO: REDO this
if (!doc) { if (!doc) {
const { actionId } = target.closest('[data-action-id]').dataset; const { actionId } = target.closest('[data-action-id]').dataset;
const { actions, attack } = this.document.system; const { actions, attack } = this.document.system;
doc = attack.id === actionId ? attack : actions?.find(a => a.id === actionId); doc = attack?.id === actionId ? attack : actions?.find(a => a.id === actionId);
} }
await doc.use(event); await doc.use(event);
} }
/**
* Use a item
* @type {ApplicationClickAction}
*/
static async #useAction(event, target) {
const doc = getDocFromElement(target);
const { actionId } = target.closest('[data-action-id]').dataset;
const { actions, attack } = doc.system;
const action = attack?.id === actionId ? attack : actions?.find(a => a.id === actionId);
await action.use(event);
}
/** /**
* Toggle a ActiveEffect * Toggle a ActiveEffect
* @type {ApplicationClickAction} * @type {ApplicationClickAction}

View file

@ -26,7 +26,6 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
removeFeature: DHBaseItemSheet.#removeFeature, removeFeature: DHBaseItemSheet.#removeFeature,
addResource: DHBaseItemSheet.#addResource, addResource: DHBaseItemSheet.#addResource,
removeResource: DHBaseItemSheet.#removeResource removeResource: DHBaseItemSheet.#removeResource
addFeature: DHBaseItemSheet.#addFeature
}, },
dragDrop: [ dragDrop: [
{ dragSelector: null, dropSelector: '.tab.features .drop-section' }, { dragSelector: null, dropSelector: '.tab.features .drop-section' },

View file

@ -8,10 +8,10 @@ export default class RegisterHandlebarsHelpers {
times: this.times, times: this.times,
damageFormula: this.damageFormula, damageFormula: this.damageFormula,
damageSymbols: this.damageSymbols, damageSymbols: this.damageSymbols,
rollParsed: this.rollParsed rollParsed: this.rollParsed,
hasProperty: foundry.utils.hasProperty,
}); });
} }
static add(a, b) { static add(a, b) {
const aNum = Number.parseInt(a); const aNum = Number.parseInt(a);
const bNum = Number.parseInt(b); const bNum = Number.parseInt(b);

View file

@ -6,6 +6,7 @@
isGlassy=true isGlassy=true
collection=effects.actives collection=effects.actives
canCreate=true canCreate=true
hideResources=true
}} }}
{{> 'daggerheart.inventory-items' {{> 'daggerheart.inventory-items'
@ -14,5 +15,6 @@
isGlassy=true isGlassy=true
collection=effects.inactives collection=effects.inactives
canCreate=true canCreate=true
hideResources=true
}} }}
</section> </section>

View file

@ -7,6 +7,7 @@
collection=document.system.features collection=document.system.features
hideControls=true hideControls=true
canCreate=true canCreate=true
showActions=true
}} }}
</div> </div>
</section> </section>

View file

@ -84,6 +84,7 @@
hideTags=true hideTags=true
hideDescription=true hideDescription=true
hideTooltip=true hideTooltip=true
hideResources=true
}} }}
</ul> </ul>
</div> </div>

View file

@ -7,6 +7,7 @@
isGlassy=true isGlassy=true
collection=effects.actives collection=effects.actives
canCreate=true canCreate=true
hideResources=true
}} }}
{{> 'daggerheart.inventory-items' {{> 'daggerheart.inventory-items'
@ -15,5 +16,6 @@
isGlassy=true isGlassy=true
collection=effects.inactives collection=effects.inactives
canCreate=true canCreate=true
hideResources=true
}} }}
</section> </section>

View file

@ -9,6 +9,7 @@
type='feature' type='feature'
collection=category.values collection=category.values
canCreate=true canCreate=true
showActions=true
}} }}
{{/if}} {{/if}}

View file

@ -19,6 +19,7 @@
collection=document.itemTypes.weapon collection=document.itemTypes.weapon
isGlassy=true isGlassy=true
canCreate=true canCreate=true
hideResources=true
}} }}
{{> 'daggerheart.inventory-items' {{> 'daggerheart.inventory-items'
title='TYPES.Item.armor' title='TYPES.Item.armor'
@ -26,6 +27,7 @@
collection=document.itemTypes.armor collection=document.itemTypes.armor
isGlassy=true isGlassy=true
canCreate=true canCreate=true
hideResources=true
}} }}
{{> 'daggerheart.inventory-items' {{> 'daggerheart.inventory-items'
title='TYPES.Item.consumable' title='TYPES.Item.consumable'

View file

@ -88,6 +88,7 @@
type=item.type type=item.type
hideTags=true hideTags=true
hideDescription=true hideDescription=true
hideResources=true
}} }}
{{/if}} {{/if}}
{{/each}} {{/each}}
@ -106,6 +107,7 @@
type='domainCard' type='domainCard'
hideTags=true hideTags=true
hideDescription=true hideDescription=true
hideResources=true
}} }}
{{/each}} {{/each}}

View file

@ -6,7 +6,7 @@
isGlassy=true isGlassy=true
collection=effects.actives collection=effects.actives
canCreate=true canCreate=true
hideResources=true
}} }}
{{> 'daggerheart.inventory-items' {{> 'daggerheart.inventory-items'
@ -15,5 +15,6 @@
isGlassy=true isGlassy=true
collection=effects.inactives collection=effects.inactives
canCreate=true canCreate=true
hideResources=true
}} }}
</section> </section>

View file

@ -10,6 +10,7 @@
collection=document.system.features collection=document.system.features
hideControls=true hideControls=true
canCreate=true canCreate=true
showActions=true
}} }}
</div> </div>
</section> </section>

View file

@ -13,6 +13,7 @@
categoryAdversary=categoryId categoryAdversary=categoryId
hideControls=true hideControls=true
collection=category.adversaries collection=category.adversaries
hideResources=true
}} }}
{{/each}} {{/each}}
</div> </div>

View file

@ -1,6 +1,11 @@
<li class="card-item" data-item-id="{{item.id}}" data-item-id="{{item.id}}"> <li class="card-item" data-item-id="{{item.id}}">
<img src="{{item.img}}" data-action="useItem" class="card-img" /> <img src="{{item.img}}" data-action="useItem" class="card-img" />
<div class="card-label"> <div class="card-label">
<div
class="menu {{#if item.system.resource}}resource-menu{{/if}} {{#if (eq item.system.resource.type 'diceValue')}}dice-menu{{/if}}">
{{#if item.system.resource}}
{{> "systems/daggerheart/templates/sheets/global/partials/item-resource.hbs"}}
{{/if}}
<div class="controls"> <div class="controls">
<a data-action="toggleVault" <a data-action="toggleVault"
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.inVault 'sendToLoadout' 'sendToVault' }}"> data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.inVault 'sendToLoadout' 'sendToVault' }}">
@ -13,6 +18,7 @@
<i class="fa-solid fa-ellipsis-vertical"></i> <i class="fa-solid fa-ellipsis-vertical"></i>
</a> </a>
</div> </div>
</div>
<div class="card-name">{{item.name}}</div> <div class="card-name">{{item.name}}</div>
</div> </div>
</li> </li>

View file

@ -18,6 +18,8 @@ Parameters:
- hideTooltip {boolean} : If true, disables the tooltip on the item image. - hideTooltip {boolean} : If true, disables the tooltip on the item image.
- hideControls {boolean} : If true, hides the controls inside inventory-item partials. - hideControls {boolean} : If true, hides the controls inside inventory-item partials.
- hideDescription {boolean} : If true, hides the item's description. - hideDescription {boolean} : If true, hides the item's description.
- hideResources {boolean} : If true, hides the item's resources.
- showActions {boolean} : If true show feature's actions.
--}} --}}
<fieldset class="{{#if isGlassy}}glassy{{/if}}"> <fieldset class="{{#if isGlassy}}glassy{{/if}}">
@ -58,6 +60,8 @@ Parameters:
hideTooltip=../hideTooltip hideTooltip=../hideTooltip
showLabels=../showLabels showLabels=../showLabels
isAction=../isAction isAction=../isAction
hideResources=../hideResources
showActions=../showActions
}} }}
{{/each}} {{/each}}

View file

@ -10,18 +10,21 @@ Parameters:
- hideTooltip {boolean} : If true, disables the tooltip on the item image. - hideTooltip {boolean} : If true, disables the tooltip on the item image.
- hideControls {boolean} : If true, hides the controls inside inventory-item partials. - hideControls {boolean} : If true, hides the controls inside inventory-item partials.
- hideDescription {boolean} : If true, hides the item's description. - hideDescription {boolean} : If true, hides the item's description.
- hideResources {boolean} : If true, hides the item's resources.
- showActions {boolean} : If true show feature's actions.
--}} --}}
<li class="inventory-item" {{#if (eq type 'action' )}}data-action-id="{{item.id}}" {{/if}} <li class="inventory-item" {{#if (eq type 'action' )}}data-action-id="{{item.id}}" {{/if}}
data-item-uuid="{{item.uuid}}" data-type="{{type}}"> data-item-uuid="{{item.uuid}}" data-type="{{type}}" draggable="true">
{{!-- Image --}} {{!-- Image --}}
<img src="{{item.img}}" class="item-img {{#if isActor}}actor-img{{/if}}" <img src="{{item.img}}" class="item-img {{#if isActor}}actor-img{{/if}}"
{{!-- I had to use the {{not}} helper because otherwise the function is called when rendering --}} data-action='{{ifThen (hasProperty item "use") "useItem" (ifThen (hasProperty item "toChat") "toChat" "editDoc") }}'
data-action="{{ifThen (not item.use) (ifThen (not item.toChat) 'editDoc' 'toChat') 'useItem' }}" {{#unless {{#unless hideTooltip}}data-tooltip="#item#{{item.uuid}}" {{/unless}} />
hideTooltip}}data-tooltip="#item#{{item.uuid}}" {{/unless}} />
<div class="item-label-wrapper">
{{!-- Name & Tags --}} {{!-- Name & Tags --}}
<div class="item-label"> <div class="item-label {{#if hideResources}}fullWidth{{/if}}">
{{!-- Item Name --}} {{!-- Item Name --}}
<div class="item-name">{{item.name}}</div> <div class="item-name">{{item.name}}</div>
@ -36,9 +39,17 @@ Parameters:
{{localize (concat 'DAGGERHEART.CONFIG.Range.' item.system.attack.range '.name')}} {{localize (concat 'DAGGERHEART.CONFIG.Range.' item.system.attack.range '.name')}}
</div> </div>
<div class="tag"> <div class="tag">
{{item.system.attack.damage.parts.0.value.dice}}{{#if item.system.attack.damage.parts.0.value.bonus}} + {{item.system.attack.damage.parts.0.value.dice}}
{{#if item.system.attack.damage.parts.0.value.bonus}} +
{{item.system.attack.damage.parts.0.value.bonus}}{{/if}} {{item.system.attack.damage.parts.0.value.bonus}}{{/if}}
({{localize (concat 'DAGGERHEART.CONFIG.DamageType.' item.system.attack.damage.parts.0.type '.abbreviation')}}) (
{{#each item.system.attack.damage.parts.0.type as |type|}}
{{localize (concat 'DAGGERHEART.CONFIG.DamageType.' type '.abbreviation')}}
{{#unless @last}}|{{/unless}}
{{/each}}
)
</div> </div>
<div class="tag"> <div class="tag">
{{localize (concat 'DAGGERHEART.CONFIG.Burden.' item.system.burden)}} {{localize (concat 'DAGGERHEART.CONFIG.Burden.' item.system.burden)}}
@ -47,6 +58,7 @@ Parameters:
{{else if (not hideLabels)}} {{else if (not hideLabels)}}
<div class="item-labels"> <div class="item-labels">
<div class="label"> <div class="label">
{{localize (concat 'DAGGERHEART.CONFIG.Traits.' item.system.attack.roll.trait '.short')}}
{{localize (concat 'DAGGERHEART.CONFIG.Range.' item.system.attack.range '.short')}} {{localize (concat 'DAGGERHEART.CONFIG.Range.' item.system.attack.range '.short')}}
<span> - </span> <span> - </span>
{{item.system.attack.damage.parts.0.value.dice}} {{item.system.attack.damage.parts.0.value.dice}}
@ -143,6 +155,15 @@ Parameters:
{{/if}} {{/if}}
{{!-- Action Block End --}} {{!-- Action Block End --}}
</div> </div>
{{#if (and (not hideResources) (eq item.system.resource.type 'simple'))}}
{{> "systems/daggerheart/templates/sheets/global/partials/item-resource.hbs"}}
{{/if}}
{{#if (and (not hideResources) item.system.quantity)}}
<div class="item-resource">
<input type="number" class="inventory-item-quantity" value="{{item.system.quantity}}" step="1" />
</div>
{{/if}}
</div>
{{!-- Controls --}} {{!-- Controls --}}
{{#unless hideControls}} {{#unless hideControls}}
@ -178,12 +199,11 @@ Parameters:
<i class="{{ifThen item.disabled 'fa-regular fa-lightbulb' 'fa-solid fa-lightbulb'}}"></i> <i class="{{ifThen item.disabled 'fa-regular fa-lightbulb' 'fa-solid fa-lightbulb'}}"></i>
</a> </a>
{{/if}} {{/if}}
{{!-- I had to use the {{not}} helper because otherwise the function is called when rendering --}} {{#if (hasProperty item "toChat")}}
{{#unless (not item.toChat)}}
<a data-action="toChat" data-tooltip="DAGGERHEART.UI.Tooltip.sendToChat"> <a data-action="toChat" data-tooltip="DAGGERHEART.UI.Tooltip.sendToChat">
<i class="fa-regular fa-message"></i> <i class="fa-regular fa-message"></i>
</a> </a>
{{/unless}} {{/if}}
<a data-action="triggerContextMenu" data-tooltip="DAGGERHEART.UI.Tooltip.moreOptions"> <a data-action="triggerContextMenu" data-tooltip="DAGGERHEART.UI.Tooltip.moreOptions">
<i class="fa-solid fa-ellipsis-vertical"></i> <i class="fa-solid fa-ellipsis-vertical"></i>
</a> </a>
@ -199,4 +219,16 @@ Parameters:
{{{item.system.description}}} {{{item.system.description}}}
</div> </div>
{{/unless}} {{/unless}}
{{#if (and (not hideResources) (eq item.system.resource.type 'diceValue'))}}
{{> "systems/daggerheart/templates/sheets/global/partials/item-resource.hbs"}}
{{/if}}
{{#if (and showActions (eq item.type 'feature'))}}
<div class="item-buttons">
{{#each item.system.actions as | action |}}
<button type="button" data-action="useAction" data-action-id="{{action.id}}">
{{action.name}}
</button>
{{/each}}
</div>
{{/if}}
</li> </li>

View file

@ -7,6 +7,7 @@
isGlassy=true isGlassy=true
collection=effects.actives collection=effects.actives
canCreate=true canCreate=true
hideResources=true
}} }}
{{> 'daggerheart.inventory-items' {{> 'daggerheart.inventory-items'
@ -15,5 +16,6 @@
isGlassy=true isGlassy=true
collection=effects.inactives collection=effects.inactives
canCreate=true canCreate=true
hideResources=true
}} }}
</section> </section>

View file

@ -6,5 +6,6 @@
isGlassy=true isGlassy=true
collection=document.system.features collection=document.system.features
canCreate=(or document.parent isGM) canCreate=(or document.parent isGM)
showActions=false
}} }}
</section> </section>