diff --git a/lang/en.json b/lang/en.json index 205a77e4..9a614b68 100755 --- a/lang/en.json +++ b/lang/en.json @@ -1099,6 +1099,17 @@ "biography": "Biography", "effects": "Effects" }, + "ContextMenu": { + "UseItem": "Use", + "Equip": "Equip", + "Unequip": "Unequip", + "Edit": "Edit", + "Delete": "Delete", + "ToLoadout": "Send to Loadout", + "ToVault": "Send to Vault", + "Consume": "Consume Item", + "SendToChat": "Send To Chat" + }, "Armor": { "Title": "Active Armor" }, diff --git a/module/applications/sheets/character.mjs b/module/applications/sheets/character.mjs index 82679ccd..665c203e 100644 --- a/module/applications/sheets/character.mjs +++ b/module/applications/sheets/character.mjs @@ -43,10 +43,11 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { makeDeathMove: this.makeDeathMove, itemQuantityDecrease: (_, button) => this.setItemQuantity(button, -1), itemQuantityIncrease: (_, button) => this.setItemQuantity(button, 1), - useAbility: this.useAbility, + toChat: this.toChat, useAdvancementCard: this.useAdvancementCard, useAdvancementAbility: this.useAdvancementAbility, toggleEquipItem: this.toggleEquipItem, + toggleVault: this.toggleVault, levelManagement: this.levelManagement, editImage: this._onEditImage }, @@ -58,11 +59,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { submitOnChange: true, closeOnSubmit: false }, - dragDrop: [ - { dragSelector: null, dropSelector: '.weapon-section' }, - { dragSelector: null, dropSelector: '.armor-section' }, - { dragSelector: '.item-list .item', dropSelector: null } - ] + dragDrop: [] }; static PARTS = { @@ -214,6 +211,109 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { return { primary: primaryTabs, secondary: secondaryTabs }; } + async _onFirstRender(context, options) { + await super._onFirstRender(context, options); + + this._createContextMenues(); + } + + _createContextMenues() { + const allOptions = { + useItem: { + name: 'DAGGERHEART.Sheets.PC.ContextMenu.UseItem', + icon: '', + callback: this.constructor.useItem.bind(this) + }, + equip: { + name: 'DAGGERHEART.Sheets.PC.ContextMenu.Equip', + icon: '', + condition: el => { + const item = foundry.utils.fromUuidSync(el.dataset.uuid); + return !item.system.equipped; + }, + callback: this.constructor.toggleEquipItem.bind(this) + }, + unequip: { + name: 'DAGGERHEART.Sheets.PC.ContextMenu.Unequip', + icon: '', + condition: el => { + const item = foundry.utils.fromUuidSync(el.dataset.uuid); + return item.system.equipped; + }, + callback: this.constructor.toggleEquipItem.bind(this) + }, + edit: { + name: 'DAGGERHEART.Sheets.PC.ContextMenu.Edit', + icon: '', + callback: this.constructor.viewObject.bind(this) + }, + delete: { + name: 'DAGGERHEART.Sheets.PC.ContextMenu.Delete', + icon: '', + callback: this.constructor.deleteItem.bind(this) + }, + sendToLoadout: { + name: 'DAGGERHEART.Sheets.PC.ContextMenu.ToLoadout', + icon: '', + condition: el => { + const item = foundry.utils.fromUuidSync(el.dataset.uuid); + return item.system.inVault; + }, + callback: this.constructor.toggleVault.bind(this) + }, + sendToVault: { + name: 'DAGGERHEART.Sheets.PC.ContextMenu.ToVault', + icon: '', + condition: el => { + const item = foundry.utils.fromUuidSync(el.dataset.uuid); + return !item.system.inVault; + }, + callback: this.constructor.toggleVault.bind(this) + }, + sendToChat: { + name: 'DAGGERHEART.Sheets.PC.ContextMenu.SendToChat', + icon: '', + callback: this.constructor.toChat.bind(this) + } + }; + + const getMenuOptions = type => () => { + let menuItems = ['class', 'subclass'].includes(type) ? [] : [allOptions.useItem]; + switch (type) { + case 'weapon': + case 'armor': + menuItems.push(...[allOptions.equip, allOptions.unequip]); + break; + case 'domainCard': + menuItems.push(...[allOptions.sendToLoadout, allOptions.sendToVault]); + break; + } + menuItems.push(...[allOptions.sendToChat, allOptions.edit, allOptions.delete]); + + return menuItems; + }; + + const menuConfigs = [ + 'armor', + 'weapon', + 'miscellaneous', + 'consumable', + 'domainCard', + 'miscellaneous', + 'ancestry', + 'community', + 'class', + 'subclass' + ]; + menuConfigs.forEach(type => { + this._createContextMenu(getMenuOptions(type), `.${type}-context-menu`, { + eventName: 'click', + parentClassHooks: false, + fixed: true + }); + }); + } + _attachPartListeners(partId, htmlElement, options) { super._attachPartListeners(partId, htmlElement, options); @@ -544,20 +644,14 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { (await game.packs.get('daggerheart.communities'))?.render(true); } - static useItem(event) { - const uuid = event.target.closest('[data-item-id]').dataset.itemId, - item = this.document.items.find(i => i.uuid === uuid); - item.use(event); + static useItem(element, button) { + const id = (button ?? element).closest('a').id, + item = this.document.items.get(id); + item.use({}); } - static async viewObject(_, button) { - const object = await fromUuid(button.dataset.value); - if (!object) return; - - const tab = button.dataset.tab; - if (tab && object.sheet._tabs) object.sheet._tabs[0].active = tab; - - if (object.sheet.editMode) object.sheet.editMode = false; + static async viewObject(element, button) { + const object = await fromUuid((button ?? element).dataset.uuid); object.sheet.render(true); } @@ -620,8 +714,8 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { this.render(); } - static async deleteItem(_, button) { - const item = await fromUuid($(button).closest('[data-item-id]')[0].dataset.itemId); + static async deleteItem(element, button) { + const item = await fromUuid((button ?? element).closest('a').dataset.uuid); await item.delete(); } @@ -655,35 +749,29 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { cls.create(msg.toObject()); } - static async useAbility(_, button) { - const item = await fromUuid(button.dataset.feature); - const type = button.dataset.type; + static async toChat(element, 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.description} ${experience.total < 0 ? experience.total : `+${experience.total}`}` + }; + const msg = new cls({ + type: 'abilityUse', + user: game.user.id, + system: systemData, + content: await foundry.applications.handlebars.renderTemplate( + 'systems/daggerheart/templates/chat/ability-use.hbs', + systemData + ) + }); - const cls = getDocumentClass('ChatMessage'); - const systemData = { - title: - type === 'ancestry' - ? game.i18n.localize('DAGGERHEART.Chat.FoundationCard.AncestryTitle') - : type === 'community' - ? game.i18n.localize('DAGGERHEART.Chat.FoundationCard.CommunityTitle') - : game.i18n.localize('DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle'), - origin: this.document.id, - img: item.img, - name: item.name, - description: item.system.description, - actions: [] - }; - const msg = new cls({ - type: 'abilityUse', - user: game.user.id, - system: systemData, - content: await foundry.applications.handlebars.renderTemplate( - 'systems/daggerheart/templates/chat/ability-use.hbs', - systemData - ) - }); - - cls.create(msg.toObject()); + cls.create(msg.toObject()); + } else { + const item = await fromUuid((button ?? element).dataset.uuid); + item.toChat(this.document.id); + } } static async useAdvancementCard(_, button) { @@ -738,8 +826,9 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { cls.create(msg.toObject()); } - static async toggleEquipItem(_, button) { - const item = this.document.items.get(button.id); + static async toggleEquipItem(element, button) { + const id = (button ?? element).closest('a').id; + const item = this.document.items.get(id); if (item.system.equipped) { await item.update({ 'system.equipped': false }); return; @@ -763,6 +852,12 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { this.render(); } + static async toggleVault(element, button) { + const id = (button ?? element).closest('a').id; + const item = this.document.items.get(id); + await item.update({ 'system.inVault': !item.system.inVault }); + } + async _onDragStart(_, event) { super._onDragStart(event); } diff --git a/module/documents/item.mjs b/module/documents/item.mjs index 54759542..ca86ce98 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -141,4 +141,32 @@ export default class DhpItem extends Item { // Display Item Card in chat return response; } + + async toChat(origin) { + const cls = getDocumentClass('ChatMessage'); + const systemData = { + title: + this.type === 'ancestry' + ? game.i18n.localize('DAGGERHEART.Chat.FoundationCard.AncestryTitle') + : this.type === 'community' + ? game.i18n.localize('DAGGERHEART.Chat.FoundationCard.CommunityTitle') + : game.i18n.localize('DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle'), + origin: origin, + img: this.img, + name: this.name, + description: this.system.description, + actions: [] + }; + const msg = new cls({ + type: 'abilityUse', + user: game.user.id, + system: systemData, + content: await foundry.applications.handlebars.renderTemplate( + 'systems/daggerheart/templates/chat/ability-use.hbs', + systemData + ) + }); + + cls.create(msg.toObject()); + } } diff --git a/styles/chat.less b/styles/chat.less index c1de3106..e075274f 100644 --- a/styles/chat.less +++ b/styles/chat.less @@ -283,6 +283,7 @@ h2 { width: 100%; text-align: center; + margin: 0; } } diff --git a/styles/daggerheart.css b/styles/daggerheart.css index c1824583..994293bf 100755 --- a/styles/daggerheart.css +++ b/styles/daggerheart.css @@ -1598,6 +1598,7 @@ .daggerheart.chat.domain-card .domain-card-title h2 { width: 100%; text-align: center; + margin: 0; } .daggerheart.chat.domain-card .ability-card-footer { display: flex; diff --git a/templates/chat/ability-use.hbs b/templates/chat/ability-use.hbs index 51d56ace..4ebaa293 100644 --- a/templates/chat/ability-use.hbs +++ b/templates/chat/ability-use.hbs @@ -1,6 +1,5 @@