diff --git a/lang/en.json b/lang/en.json index ce8f0295..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" }, @@ -1295,6 +1306,7 @@ "Severe": "Severe" }, "Evasion": "Evasion", + "HitPoints": "Hit Points", "ClassFeatures": "Class Features", "Subclasses": "Subclasses", "Guide": { diff --git a/module/applications/sheets/character.mjs b/module/applications/sheets/character.mjs index 7b8f1c04..11bbd18f 100644 --- a/module/applications/sheets/character.mjs +++ b/module/applications/sheets/character.mjs @@ -44,10 +44,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 }, @@ -59,11 +60,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 = { @@ -215,6 +212,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); @@ -552,20 +652,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); } @@ -628,8 +722,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(); } @@ -663,35 +757,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) { @@ -746,8 +834,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; @@ -771,6 +860,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/config/domainConfig.mjs b/module/config/domainConfig.mjs index 3ecb0bd1..136b077e 100644 --- a/module/config/domainConfig.mjs +++ b/module/config/domainConfig.mjs @@ -2,56 +2,55 @@ export const domains = { arcana: { id: 'arcana', label: 'DAGGERHEART.Domains.arcana.label', - src: 'icons/magic/symbols/circled-gem-pink.webp', + src: 'systems/daggerheart/assets/icons/domains/arcana.svg', description: 'DAGGERHEART.Domains.Arcana' }, blade: { id: 'blade', label: 'DAGGERHEART.Domains.blade.label', - src: 'icons/weapons/swords/sword-broad-crystal-paired.webp', + src: 'systems/daggerheart/assets/icons/domains/blade.svg', description: 'DAGGERHEART.Domains.Blade' }, bone: { id: 'bone', label: 'DAGGERHEART.Domains.bone.label', - src: 'icons/skills/wounds/bone-broken-marrow-red.webp', + src: 'systems/daggerheart/assets/icons/domains/bone.svg', description: 'DAGGERHEART.Domains.Bone' }, codex: { id: 'codex', label: 'DAGGERHEART.Domains.codex.label', - src: 'icons/sundries/books/book-embossed-jewel-gold-purple.webp', + src: 'systems/daggerheart/assets/icons/domains/codex.svg', description: 'DAGGERHEART.Domains.Codex' }, grace: { id: 'grace', label: 'DAGGERHEART.Domains.grace.label', - src: 'icons/skills/movement/feet-winged-boots-glowing-yellow.webp', + src: 'systems/daggerheart/assets/icons/domains/grace.svg', description: 'DAGGERHEART.Domains.Grace' }, midnight: { id: 'midnight', label: 'DAGGERHEART.Domains.midnight.label', - src: 'icons/environment/settlement/watchtower-castle-night.webp', - background: 'systems/daggerheart/assets/backgrounds/MidnightBackground.webp', + src: 'systems/daggerheart/assets/icons/domains/midnight.svg', description: 'DAGGERHEART.Domains.Midnight' }, sage: { id: 'sage', label: 'DAGGERHEART.Domains.sage.label', - src: 'icons/sundries/misc/pipe-wooden-straight-brown.webp', + src: 'systems/daggerheart/assets/icons/domains/sage.svg', description: 'DAGGERHEART.Domains.Sage' }, splendor: { id: 'splendor', label: 'DAGGERHEART.Domains.splendor.label', - src: 'icons/magic/control/control-influence-crown-gold.webp', + src: 'systems/daggerheart/assets/icons/domains/splendor.svg', description: 'DAGGERHEART.Domains.Splendor' }, valor: { id: 'valor', label: 'DAGGERHEART.Domains.valor.label', - src: 'icons/magic/control/control-influence-rally-purple.webp', + src: 'systems/daggerheart/assets/icons/domains/valor.svg', description: 'DAGGERHEART.Domains.Valor' } }; diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 9e467cab..8d6e2e41 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -30,7 +30,10 @@ export default class DhCharacter extends BaseDataActor { return { resources: new fields.SchemaField({ - hitPoints: resourceField(6), + hitPoints: new fields.SchemaField({ + value: new foundry.data.fields.NumberField({ initial: 0, integer: true }), + bonus: new foundry.data.fields.NumberField({ initial: 0, integer: true }) + }), stress: resourceField(6), hope: resourceField(6) }), @@ -243,7 +246,7 @@ export default class DhCharacter extends BaseDataActor { experience.total = experience.value + experience.bonus; } - this.resources.hitPoints.maxTotal = this.resources.hitPoints.max + this.resources.hitPoints.bonus; + this.resources.hitPoints.maxTotal = (this.class.value?.system?.hitPoints ?? 0) + this.resources.hitPoints.bonus; this.resources.stress.maxTotal = this.resources.stress.max + this.resources.stress.bonus; this.evasion.total = (this.class?.evasion ?? 0) + this.evasion.bonus; this.proficiency.total = this.proficiency.value + this.proficiency.bonus; diff --git a/module/data/item/class.mjs b/module/data/item/class.mjs index cd69648d..46ec6ff8 100644 --- a/module/data/item/class.mjs +++ b/module/data/item/class.mjs @@ -20,8 +20,14 @@ export default class DHClass extends BaseDataItem { ...super.defineSchema(), domains: new fields.ArrayField(new fields.StringField(), { max: 2 }), classItems: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }), - - evasion: new fields.NumberField({ initial: 0, integer: true }), + hitPoints: new fields.NumberField({ + required: true, + integer: true, + min: 1, + initial: 5, + label: 'DAGGERHEART.Sheets.Class.HitPoints' + }), + evasion: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.Sheets.Class.Evasion' }), hopeFeatures: new foundry.data.fields.ArrayField(new ActionField()), classFeatures: new foundry.data.fields.ArrayField(new ActionField()), subclasses: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }), 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 ec650b61..b6508ed8 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 @@
-
{{title}}

{{name}}

diff --git a/templates/sheets/actors/character/loadout.hbs b/templates/sheets/actors/character/loadout.hbs index 1edf3df4..e80aaa80 100644 --- a/templates/sheets/actors/character/loadout.hbs +++ b/templates/sheets/actors/character/loadout.hbs @@ -29,9 +29,9 @@ {{/if}} {{#if this.abilities.loadout.listView}} - {{> 'systems/daggerheart/templates/sheets/global/partials/inventory-fieldset-items.hbs' title=(localize 'DAGGERHEART.Sheets.PC.Tabs.Vault') type='domainCard' isGlassy=true cardView='list'}} + {{> 'systems/daggerheart/templates/sheets/global/partials/inventory-fieldset-items.hbs' title=(localize 'DAGGERHEART.Sheets.PC.Tabs.Vault') type='domainCard' isVault=true isGlassy=true cardView='list'}} {{else}} - {{> 'systems/daggerheart/templates/sheets/global/partials/inventory-fieldset-items.hbs' title=(localize 'DAGGERHEART.Sheets.PC.Tabs.Vault') type='domainCard' isGlassy=true cardView='card'}} + {{> 'systems/daggerheart/templates/sheets/global/partials/inventory-fieldset-items.hbs' title=(localize 'DAGGERHEART.Sheets.PC.Tabs.Vault') type='domainCard' isVault=true isGlassy=true cardView='card'}} {{/if}} diff --git a/templates/sheets/actors/character/sidebar.hbs b/templates/sheets/actors/character/sidebar.hbs index 8e4891dc..bba7b3e3 100644 --- a/templates/sheets/actors/character/sidebar.hbs +++ b/templates/sheets/actors/character/sidebar.hbs @@ -111,7 +111,7 @@
- +
{{/each}} diff --git a/templates/sheets/global/partials/domain-card-item.hbs b/templates/sheets/global/partials/domain-card-item.hbs index 9198c8af..55662833 100644 --- a/templates/sheets/global/partials/domain-card-item.hbs +++ b/templates/sheets/global/partials/domain-card-item.hbs @@ -1,5 +1,5 @@
  • - +
    {{#if (eq type 'weapon')}} @@ -24,8 +24,8 @@ {{/unless}} {{/if}} - - + +
    {{item.name}}
    diff --git a/templates/sheets/global/partials/inventory-fieldset-items.hbs b/templates/sheets/global/partials/inventory-fieldset-items.hbs index 3014a35c..10f34e3d 100644 --- a/templates/sheets/global/partials/inventory-fieldset-items.hbs +++ b/templates/sheets/global/partials/inventory-fieldset-items.hbs @@ -4,7 +4,7 @@ {{#unless (eq cardView 'card') }} {{#each document.items as |item|}} {{#if (eq item.type ../type)}} - {{#unless (or (eq ../type 'ancestry') (eq item.type 'class') (eq item.type 'subclass'))}} + {{#unless (or (eq ../type 'ancestry') (eq item.type 'class') (eq item.type 'subclass') (and (eq ../type 'domainCard') (or (and item.system.inVault (not ../isVault)) (and (not item.system.inVault) ../isVault))))}} {{> 'systems/daggerheart/templates/sheets/global/partials/inventory-item.hbs' item=item type=../type}} {{/unless}} {{/if}} diff --git a/templates/sheets/global/partials/inventory-item.hbs b/templates/sheets/global/partials/inventory-item.hbs index 093c804f..640a8415 100644 --- a/templates/sheets/global/partials/inventory-item.hbs +++ b/templates/sheets/global/partials/inventory-item.hbs @@ -1,5 +1,5 @@
  • - +
    {{item.name}}
    {{#if (eq type 'weapon')}} @@ -114,17 +114,17 @@ {{/if}} {{#if (eq type 'domainCard')}} {{#unless item.system.inVault}} - + {{else}} - + {{/unless}} {{/if}} - - + +
  • \ No newline at end of file diff --git a/templates/sheets/items/class/settings.hbs b/templates/sheets/items/class/settings.hbs index 1a211f2b..47e3ddb9 100644 --- a/templates/sheets/items/class/settings.hbs +++ b/templates/sheets/items/class/settings.hbs @@ -3,11 +3,10 @@ data-tab='{{tabs.settings.id}}' data-group='{{tabs.settings.group}}' > - -
    +
    {{localize tabs.settings.label}} - {{localize "DAGGERHEART.Sheets.Class.Evasion"}} - {{formField systemFields.evasion value=source.system.evasion}} + {{formGroup systemFields.hitPoints value=source.system.hitPoints localize=true}} + {{formGroup systemFields.evasion value=source.system.evasion localize=true}}