From a2a2661033e4ce5d5ebba4e568c047858c0c2a8f Mon Sep 17 00:00:00 2001 From: CPTN_Cosmo Date: Sat, 28 Jun 2025 20:36:01 +0200 Subject: [PATCH 1/9] Update issue templates (#196) --- .github/ISSUE_TEMPLATE/bug_report.md | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..938abe7c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,34 @@ +--- +name: Bug report +about: Create a report to help us improve +title: "[BUG] - " +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Setup Information:** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Foundry Version [e.g. v13 b342] +- System Version [e.g. main-3593f44] + + +**Additional context** +Add any other context about the problem here. From 778e569037f78066638d4e75175b0f3e538893c2 Mon Sep 17 00:00:00 2001 From: Murilo Brito <91566541+moliloo@users.noreply.github.com> Date: Sat, 28 Jun 2025 15:45:59 -0300 Subject: [PATCH 2/9] fix death roll function (#197) --- module/applications/sheets/character.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/applications/sheets/character.mjs b/module/applications/sheets/character.mjs index a114e1c1..8570b5f3 100644 --- a/module/applications/sheets/character.mjs +++ b/module/applications/sheets/character.mjs @@ -647,7 +647,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { } static async makeDeathMove() { - if (this.document.system.resources.hitPoints.value === this.document.system.resources.hitPoints.max) { + if (this.document.system.resources.hitPoints.value >= this.document.system.resources.hitPoints.maxTotal) { await new DhpDeathMove(this.document).render(true); } } From b25e1cec78890cd0b6e68ff580b4ce5b77dcd48e Mon Sep 17 00:00:00 2001 From: IrkTheImp <41175833+IrkTheImp@users.noreply.github.com> Date: Sat, 28 Jun 2025 14:00:42 -0500 Subject: [PATCH 3/9] Irk/83 homebrew currency (#193) * add homebrew options to rename currency names * add title. remove localization from settings file since it didn't work. * use enabled toggle to use localized initial label values. * cleanup --- lang/en.json | 9 ++++++ .../settings/homebrewSettings.mjs | 29 +++++++++++++++-- module/applications/sheets/character.mjs | 12 +++++++ module/config/generalConfig.mjs | 21 ++++++++---- module/data/settings/Homebrew.mjs | 32 +++++++++++++++++++ templates/settings/homebrew-settings.hbs | 17 ++++++++-- .../sheets/actors/character/inventory.hbs | 14 ++++---- templates/sheets/parts/gold.hbs | 10 +++--- 8 files changed, 121 insertions(+), 23 deletions(-) diff --git a/lang/en.json b/lang/en.json index 77a14f75..90250d05 100755 --- a/lang/en.json +++ b/lang/en.json @@ -99,6 +99,15 @@ "FIELDS": { "maxFear": { "label": "Max Fear" }, "traitArray": { "label": "Initial Trait Modifiers" } + }, + "Currency": { + "enabled": "Enable Overrides", + "title": "Currency Overrides", + "currencyName": "Currency Name", + "coinName": "Coin Name", + "handfullName": "Handfull Name", + "bagName": "Bag Name", + "chestName": "Chest Name" } }, "Resources": { diff --git a/module/applications/settings/homebrewSettings.mjs b/module/applications/settings/homebrewSettings.mjs index d59bc35c..e67afb1b 100644 --- a/module/applications/settings/homebrewSettings.mjs +++ b/module/applications/settings/homebrewSettings.mjs @@ -24,14 +24,16 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli editItem: this.editItem, removeItem: this.removeItem, resetMoves: this.resetMoves, - save: this.save + save: this.save, + reset: this.reset }, form: { handler: this.updateData, submitOnChange: true } }; static PARTS = { main: { - template: 'systems/daggerheart/templates/settings/homebrew-settings.hbs' + template: 'systems/daggerheart/templates/settings/homebrew-settings.hbs', + scrollable: [''] } }; @@ -154,4 +156,27 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Homebrew, this.settings.toObject()); this.close(); } + + static async reset() { + const resetSettings = new DhHomebrew(); + let localizedSettings = this.localizeObject(resetSettings); + this.settings.updateSource(localizedSettings); + this.render(); + } + + localizeObject(obj) { + for (let key in obj) { + if (obj.hasOwnProperty(key)) { + const value = obj[key]; + if (typeof value === 'object' && value !== null) { + obj[key] = this.localizeObject(value); + } else { + if (typeof value === 'string' && value.startsWith('DAGGERHEART.')) { + obj[key] = game.i18n.localize(value); + } + } + } + } + return obj; + } } diff --git a/module/applications/sheets/character.mjs b/module/applications/sheets/character.mjs index 8570b5f3..b3e68609 100644 --- a/module/applications/sheets/character.mjs +++ b/module/applications/sheets/character.mjs @@ -409,9 +409,21 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { quantity: game.i18n.localize('DAGGERHEART.Sheets.PC.InventoryTab.QuantityTitle') }, items: this.document.items.filter(x => x.type === 'armor') + }, + currency: { + title: game.i18n.localize('DAGGERHEART.Sheets.PC.Gold.Title'), + coins: game.i18n.localize('DAGGERHEART.Sheets.PC.Gold.Coins'), + handfulls: game.i18n.localize('DAGGERHEART.Sheets.PC.Gold.Handfulls'), + bags: game.i18n.localize('DAGGERHEART.Sheets.PC.Gold.Bags'), + chests: game.i18n.localize('DAGGERHEART.Sheets.PC.Gold.Chests') } }; + const homebrewCurrency = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Homebrew).currency; + if (homebrewCurrency.enabled) { + context.inventory.currency = homebrewCurrency; + } + if (context.inventory.length === 0) { context.inventory = Array(1).fill(Array(5).fill([])); } diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index ccbe2d21..7b6fba4e 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -163,13 +163,15 @@ export const defaultRestOptions = { id: 'repairArmor', name: game.i18n.localize('DAGGERHEART.Downtime.ShortRest.RepairArmor.Name'), img: 'icons/skills/trades/smithing-anvil-silver-red.webp', - description: game.i18n.localize('DAGGERHEART.Downtime.ShortRest.RepairArmor.Description') + description: game.i18n.localize('DAGGERHEART.Downtime.ShortRest.RepairArmor.Description'), + actions: [] }, prepare: { id: 'prepare', name: game.i18n.localize('DAGGERHEART.Downtime.ShortRest.Prepare.Name'), img: 'icons/skills/trades/academics-merchant-scribe.webp', - description: game.i18n.localize('DAGGERHEART.Downtime.ShortRest.Prepare.Description') + description: game.i18n.localize('DAGGERHEART.Downtime.ShortRest.Prepare.Description'), + actions: [] } }), longRest: () => ({ @@ -177,31 +179,36 @@ export const defaultRestOptions = { id: 'tendToWounds', name: game.i18n.localize('DAGGERHEART.Downtime.LongRest.TendToWounds.Name'), img: 'icons/magic/life/cross-worn-green.webp', - description: game.i18n.localize('DAGGERHEART.Downtime.LongRest.TendToWounds.Description') + description: game.i18n.localize('DAGGERHEART.Downtime.LongRest.TendToWounds.Description'), + actions: [] }, clearStress: { id: 'clearStress', name: game.i18n.localize('DAGGERHEART.Downtime.LongRest.ClearStress.Name'), img: 'icons/magic/perception/eye-ringed-green.webp', - description: game.i18n.localize('DAGGERHEART.Downtime.LongRest.ClearStress.Description') + description: game.i18n.localize('DAGGERHEART.Downtime.LongRest.ClearStress.Description'), + actions: [] }, repairArmor: { id: 'repairArmor', name: game.i18n.localize('DAGGERHEART.Downtime.LongRest.RepairArmor.Name'), img: 'icons/skills/trades/smithing-anvil-silver-red.webp', - description: game.i18n.localize('DAGGERHEART.Downtime.LongRest.RepairArmor.Description') + description: game.i18n.localize('DAGGERHEART.Downtime.LongRest.RepairArmor.Description'), + actions: [] }, prepare: { id: 'prepare', name: game.i18n.localize('DAGGERHEART.Downtime.LongRest.Prepare.Name'), img: 'icons/skills/trades/academics-merchant-scribe.webp', - description: game.i18n.localize('DAGGERHEART.Downtime.LongRest.Prepare.Description') + description: game.i18n.localize('DAGGERHEART.Downtime.LongRest.Prepare.Description'), + actions: [] }, workOnAProject: { id: 'workOnAProject', name: game.i18n.localize('DAGGERHEART.Downtime.LongRest.WorkOnAProject.Name'), img: 'icons/skills/social/thumbsup-approval-like.webp', - description: game.i18n.localize('DAGGERHEART.Downtime.LongRest.WorkOnAProject.Description') + description: game.i18n.localize('DAGGERHEART.Downtime.LongRest.WorkOnAProject.Description'), + actions: [] } }), custom: { diff --git a/module/data/settings/Homebrew.mjs b/module/data/settings/Homebrew.mjs index 3aef56d6..d26de253 100644 --- a/module/data/settings/Homebrew.mjs +++ b/module/data/settings/Homebrew.mjs @@ -16,6 +16,38 @@ export default class DhHomebrew extends foundry.abstract.DataModel { traitArray: new fields.ArrayField(new fields.NumberField({ required: true, integer: true }), { initial: () => [2, 1, 1, 0, 0, -1] }), + currency: new fields.SchemaField({ + enabled: new fields.BooleanField({ + required: true, + initial: false, + label: 'DAGGERHEART.Settings.Homebrew.Currency.enabled' + }), + title: new fields.StringField({ + required: true, + initial: 'Gold', + label: 'DAGGERHEART.Settings.Homebrew.Currency.currencyName' + }), + coins: new fields.StringField({ + required: true, + initial: 'Coins', + label: 'DAGGERHEART.Settings.Homebrew.Currency.coinName' + }), + handfulls: new fields.StringField({ + required: true, + initial: 'Handfulls', + label: 'DAGGERHEART.Settings.Homebrew.Currency.handfullName' + }), + bags: new fields.StringField({ + required: true, + initial: 'Bags', + label: 'DAGGERHEART.Settings.Homebrew.Currency.bagName' + }), + chests: new fields.StringField({ + required: true, + initial: 'Chests', + label: 'DAGGERHEART.Settings.Homebrew.Currency.chestName' + }) + }), restMoves: new fields.SchemaField({ longRest: new fields.SchemaField({ nrChoices: new fields.NumberField({ required: true, integer: true, min: 1, initial: 2 }), diff --git a/templates/settings/homebrew-settings.hbs b/templates/settings/homebrew-settings.hbs index 2e6ddb10..e32830fe 100644 --- a/templates/settings/homebrew-settings.hbs +++ b/templates/settings/homebrew-settings.hbs @@ -1,4 +1,4 @@ -
+
{{formGroup settingFields.schema.fields.maxFear value=settingFields._source.maxFear localize=true}}

{{localize "DAGGERHEART.Settings.Homebrew.FIELDS.traitArray.label"}}

@@ -9,7 +9,20 @@
{{/each}} -
+ + +
+ + {{localize "DAGGERHEART.Settings.Homebrew.Currency.title"}} + + {{formGroup settingFields.schema.fields.currency.fields.enabled value=settingFields._source.currency.enabled localize=true}} + {{formGroup settingFields.schema.fields.currency.fields.title value=settingFields._source.currency.title localize=true}} + {{formGroup settingFields.schema.fields.currency.fields.coins value=settingFields._source.currency.coins localize=true}} + {{formGroup settingFields.schema.fields.currency.fields.handfulls value=settingFields._source.currency.handfulls localize=true}} + {{formGroup settingFields.schema.fields.currency.fields.bags value=settingFields._source.currency.bags localize=true}} + {{formGroup settingFields.schema.fields.currency.fields.chests value=settingFields._source.currency.chests localize=true}} + +
{{localize "DAGGERHEART.Settings.Homebrew.DowntimeMoves"}} diff --git a/templates/sheets/actors/character/inventory.hbs b/templates/sheets/actors/character/inventory.hbs index 0d9f312a..22b32d3f 100644 --- a/templates/sheets/actors/character/inventory.hbs +++ b/templates/sheets/actors/character/inventory.hbs @@ -12,7 +12,7 @@ - +
{{> 'systems/daggerheart/templates/sheets/global/partials/inventory-fieldset-items.hbs' title=(localize 'TYPES.Item.weapon') type='weapon' isGlassy=true}} {{> 'systems/daggerheart/templates/sheets/global/partials/inventory-fieldset-items.hbs' title=(localize 'TYPES.Item.armor') type='armor' isGlassy=true}} @@ -20,23 +20,23 @@ {{> 'systems/daggerheart/templates/sheets/global/partials/inventory-fieldset-items.hbs' title=(localize 'TYPES.Item.miscellaneous') type='miscellaneous' isGlassy=true}}
-
+
- {{localize "DAGGERHEART.Sheets.PC.Gold.Coins"}} + {{localize this.inventory.currency.coins}} {{formInput systemFields.gold.fields.coins value=source.system.gold.coins enriched=source.system.gold.coins localize=true toggled=true}}
- {{localize "DAGGERHEART.Sheets.PC.Gold.Handfulls"}} + {{localize this.inventory.currency.handfulls}} {{formInput systemFields.gold.fields.handfulls value=source.system.gold.handfulls enriched=source.system.gold.handfulls localize=true toggled=true}}
- {{localize "DAGGERHEART.Sheets.PC.Gold.Bags"}} + {{localize this.inventory.currency.bags}} {{formInput systemFields.gold.fields.bags value=source.system.gold.bags enriched=source.system.gold.bags localize=true toggled=true}}
- {{localize "DAGGERHEART.Sheets.PC.Gold.Chests"}} + {{localize this.inventory.currency.chests}} {{formInput systemFields.gold.fields.chests value=source.system.gold.chests enriched=source.system.gold.chests localize=true toggled=true}}
+
- \ No newline at end of file diff --git a/templates/sheets/parts/gold.hbs b/templates/sheets/parts/gold.hbs index 83634403..d25894b5 100644 --- a/templates/sheets/parts/gold.hbs +++ b/templates/sheets/parts/gold.hbs @@ -1,10 +1,10 @@
- {{localize "DAGGERHEART.Sheets.PC.Gold.Title"}} + {{localize this.inventory.currency.title}}
- {{localize "DAGGERHEART.Sheets.PC.Gold.Coins"}} + {{localize this.inventory.currency.coins}}
@@ -27,7 +27,7 @@
- {{localize "DAGGERHEART.Sheets.PC.Gold.Handfulls"}} + {{localize this.inventory.currency.handfulls}}
@@ -50,7 +50,7 @@
- {{localize "DAGGERHEART.Sheets.PC.Gold.Bags"}} + {{localize this.inventory.currency.bags}}
@@ -76,7 +76,7 @@
- {{localize "DAGGERHEART.Sheets.PC.Gold.Chests"}} + {{localize this.inventory.currency.chests}}
From 0a5f9c8905e0aaffe4de7127e71a49d96b574983 Mon Sep 17 00:00:00 2001 From: Murilo Brito <91566541+moliloo@users.noreply.github.com> Date: Sat, 28 Jun 2025 18:48:35 -0300 Subject: [PATCH 4/9] fix char setup dialog overflow (#206) --- styles/characterCreation.less | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/styles/characterCreation.less b/styles/characterCreation.less index 49f7e74a..e6548d21 100644 --- a/styles/characterCreation.less +++ b/styles/characterCreation.less @@ -1,6 +1,7 @@ +@import './less/utils/colors.less'; + .theme-light .daggerheart.dh-style.dialog.character-creation { .tab-navigation nav a .descriptor { - background: red; background-image: url('../assets/parchments/dh-parchment-dark.png'); } .main-selections-container { @@ -15,6 +16,10 @@ .daggerheart.dh-style.dialog.character-creation { .window-content { gap: 16px; + + .tab { + overflow-y: auto; + } } .tab-navigation { From 7114a9e7496de9278c207cb97222e0e8bfa188d0 Mon Sep 17 00:00:00 2001 From: Jacob <124112219+jacobwojoski@users.noreply.github.com> Date: Sat, 28 Jun 2025 19:54:57 -0400 Subject: [PATCH 5/9] Feature/211 readme install updates (#212) * Update README.md * Update README.md * Update README.md --- README.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9c58fece..5fecbd3e 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,19 @@ # Daggerheart +## Table of Contents +- [Overview](#overview) +- [User Install Guide](#user-install) +- [Developer Setup](#developer-setup) +- [Contribution Info](#contributing) -This is a repo for a Foundry VTT implementation of daggerheart. It is not associated with Critical Role or Darrington Press. +## Overivew +This is a community repo for a Foundry VTT implementation of Daggerheart. It is not associated with Critical Role or Darrington Press. -## Setup +## User Install +1. **(Not Yet Supported - No Releases Yet)** Pasting `https://raw.githubusercontent.com/Foundryborne/daggerheart/refs/heads/main/system.json` into the Install System dialog on the Setup menu of the application. +2. **(Not Yet Supported - No Releases Yet)** Browsing the repository's Releases page, where you can copy any system.json link for use in the Install System dialog. +3. **(Not Yet Supported - No Releases Yet)** Downloading one of the .zip archives from the Releases page and extracting it into your foundry Data folder, under Data/systems/daggerheart. +## Development Setup - Open a terminal in the directory with the repo `cd //` - NOTE: The repo should be placed in the system files are or somewhere else and a link (if on linux) is placed in the system directory - NOTE: Linux link can be made using `ln -snf daggerheart` inside the system folder @@ -27,4 +37,4 @@ Now you should be able to build the app using `npm start` ## Contributing -Looking to contribute to the project? Look no further, check out our [contributing guide](contributing.md), and keep the [Code of Conduct](coc.md) in mind when working on things. \ No newline at end of file +Looking to contribute to the project? Look no further, check out our [contributing guide](contributing.md), and keep the [Code of Conduct](coc.md) in mind when working on things. From 7135716da9ac51576771033f01d9842f809515f2 Mon Sep 17 00:00:00 2001 From: joaquinpereyra98 <24190917+joaquinpereyra98@users.noreply.github.com> Date: Sat, 28 Jun 2025 23:44:57 -0300 Subject: [PATCH 6/9] Feature/178 searchbar logic to items in character sheet (#209) * REFACTOR: remove DhpApplicationMixin REFACTOR: remove getEmbeddedDocument method from Item class REFACTOR: remove prepareData method from Actor class REFACTOR: remove _preUpdate method from Actor class * REFACTOR: rename dhpItem to DHItem REFACTOR: improvement Item#isInventoryItem getter REFACTOR: simplify Item's createDialog static method. REFACTOR: remove documentCreate template * FEAT: add SearchFilter for character-sheet Inventory and DomainCards FEAT: simplify the preparetion of inventory context --------- Co-authored-by: Joaquin Pereyra --- daggerheart.mjs | 2 +- module/applications/daggerheart-sheet.mjs | 48 ------- module/applications/sheets/character.mjs | 110 +++++++++++++- module/data/item/armor.mjs | 3 +- module/data/item/base.mjs | 4 +- module/data/item/consumable.mjs | 3 +- module/data/item/miscellaneous.mjs | 3 +- module/data/item/weapon.mjs | 6 +- module/documents/_module.mjs | 2 +- module/documents/actor.mjs | 8 -- module/documents/item.mjs | 120 +++++++--------- styles/daggerheart.css | 4 + styles/less/actors/character/inventory.less | 135 +++++++++--------- .../sheets/actors/character/inventory.hbs | 2 +- templates/sheets/actors/character/loadout.hbs | 2 +- .../global/partials/domain-card-item.hbs | 2 +- templates/sidebar/documentCreate.hbs | 45 ------ 17 files changed, 245 insertions(+), 254 deletions(-) delete mode 100644 module/applications/daggerheart-sheet.mjs delete mode 100644 templates/sidebar/documentCreate.hbs diff --git a/daggerheart.mjs b/daggerheart.mjs index c08fed77..909324b4 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -62,7 +62,7 @@ Hooks.once('init', () => { CONFIG.Dice.rolls = [...CONFIG.Dice.rolls, ...[DHRoll, DualityRoll, D20Roll, DamageRoll]]; CONFIG.MeasuredTemplate.objectClass = DhMeasuredTemplate; - CONFIG.Item.documentClass = documents.DhpItem; + CONFIG.Item.documentClass = documents.DHItem; //Registering the Item DataModel CONFIG.Item.dataModels = models.items.config; diff --git a/module/applications/daggerheart-sheet.mjs b/module/applications/daggerheart-sheet.mjs deleted file mode 100644 index 32d5212e..00000000 --- a/module/applications/daggerheart-sheet.mjs +++ /dev/null @@ -1,48 +0,0 @@ -export default function DhpApplicationMixin(Base) { - return class DhpSheet extends Base { - static applicationType = 'sheets'; - static documentType = ''; - - static get defaultOptions() { - return Object.assign(super.defaultOptions, { - classes: ['daggerheart', 'sheet', this.documentType], - template: `systems/${SYSTEM.id}/templates/${this.applicationType}/${this.documentType}.hbs`, - height: 'auto', - submitOnChange: true, - submitOnClose: false, - width: 450 - }); - } - - /** @override */ - get title() { - const { documentName, type, name } = this.object; - // const typeLabel = game.i18n.localize(CONFIG[documentName].typeLabels[type]); - const typeLabel = documentName; - return `[${typeLabel}] ${name}`; - } - - // async _renderOuter() { - // const html = await super._renderOuter(); - // // const overlaySrc = "systems/amia/assets/ThePrimordial.png"; - // const overlay = `
` - // $(html).find('.window-header').prepend(overlay); - // return html; - // } - - activateListeners(html) { - super.activateListeners(html); - html.on('click', '[data-action]', this.#onClickAction.bind(this)); - } - - async #onClickAction(event) { - event.preventDefault(); - const button = event.currentTarget; - const action = button.dataset.action; - - return this._handleAction(action, event, button); - } - - async _handleAction(action, event, button) {} - }; -} diff --git a/module/applications/sheets/character.mjs b/module/applications/sheets/character.mjs index b3e68609..ad294aff 100644 --- a/module/applications/sheets/character.mjs +++ b/module/applications/sheets/character.mjs @@ -56,7 +56,6 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { resizable: true }, form: { - handler: this.updateForm, submitOnChange: true, closeOnSubmit: false }, @@ -218,6 +217,15 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { this._createContextMenues(); } + /** @inheritDoc */ + async _onRender(context, options) { + await super._onRender(context, options); + + this._createSearchFilter(); + } + + /* -------------------------------------------- */ + _createContextMenues() { const allOptions = { useItem: { @@ -431,11 +439,105 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { return context; } - static async updateForm(event, _, formData) { - await this.document.update(formData.object); - this.render(); + /* -------------------------------------------- */ + /* Search Filter */ + /* -------------------------------------------- */ + + /** + * The currently active search filter. + * @type {foundry.applications.ux.SearchFilter} + */ + #search = {}; + + /** + * Track which item IDs are currently displayed due to a search filter. + * @type {{ inventory: Set, loadout: Set }} + */ + #filteredItems = { + inventory: new Set(), + loadout: new Set() + }; + + /** + * Create and initialize search filter instances for the inventory and loadout sections. + * + * Sets up two {@link foundry.applications.ux.SearchFilter} instances: + * - One for the inventory, which filters items in the inventory grid. + * - One for the loadout, which filters items in the loadout/card grid. + * @private + */ + _createSearchFilter() { + //Filters could be a application option if needed + const filters = [ + { + key: 'inventory', + input: 'input[type="search"].search-inventory', + content: '[data-application-part="inventory"] .items-section', + callback: this._onSearchFilterInventory.bind(this) + }, + { + key: 'loadout', + input: 'input[type="search"].search-loadout', + content: '[data-application-part="loadout"] .items-section', + callback: this._onSearchFilterCard.bind(this) + } + ]; + + for (const { key, input, content, callback } of filters) { + const filter = new foundry.applications.ux.SearchFilter({ + inputSelector: input, + contentSelector: content, + callback + }); + filter.bind(this.element); + this.#search[key] = filter; + } } + /** + * Handle invetory items search and filtering. + * @param {KeyboardEvent} event The keyboard input event. + * @param {string} query The input search string. + * @param {RegExp} rgx The regular expression query that should be matched against. + * @param {HTMLElement} html The container to filter items from. + * @protected + */ + _onSearchFilterInventory(event, query, rgx, html) { + this.#filteredItems.inventory.clear(); + + for (const ul of html.querySelectorAll('.items-list')) { + for (const li of ul.querySelectorAll('.inventory-item')) { + const item = this.document.items.get(li.dataset.itemId); + const match = !query || foundry.applications.ux.SearchFilter.testQuery(rgx, item.name); + if (match) this.#filteredItems.inventory.add(item.id); + li.hidden = !match; + } + } + } + + /** + * Handle card items search and filtering. + * @param {KeyboardEvent} event The keyboard input event. + * @param {string} query The input search string. + * @param {RegExp} rgx The regular expression query that should be matched against. + * @param {HTMLElement} html The container to filter items from. + * @protected + */ + _onSearchFilterCard(event, query, rgx, html) { + this.#filteredItems.loadout.clear(); + + const elements = html.querySelectorAll('.items-list .inventory-item, .card-list .card-item'); + + for (const li of elements) { + const item = this.document.items.get(li.dataset.itemId); + const match = !query || foundry.applications.ux.SearchFilter.testQuery(rgx, item.name); + if (match) this.#filteredItems.loadout.add(item.id); + li.hidden = !match; + } + } + + /* -------------------------------------------- */ + async mapFeatureType(data, configType) { return await Promise.all( data.map(async x => { diff --git a/module/data/item/armor.mjs b/module/data/item/armor.mjs index c7f5af0b..ffd00a23 100644 --- a/module/data/item/armor.mjs +++ b/module/data/item/armor.mjs @@ -9,7 +9,8 @@ export default class DHArmor extends BaseDataItem { label: 'TYPES.Item.armor', type: 'armor', hasDescription: true, - isQuantifiable: true + isQuantifiable: true, + isInventoryItem: true, }); } diff --git a/module/data/item/base.mjs b/module/data/item/base.mjs index 219b43aa..0df64a3e 100644 --- a/module/data/item/base.mjs +++ b/module/data/item/base.mjs @@ -7,6 +7,7 @@ import { actionsTypes } from '../action/_module.mjs'; * @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 */ const fields = foundry.data.fields; @@ -18,7 +19,8 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { label: 'Base Item', type: 'base', hasDescription: false, - isQuantifiable: false + isQuantifiable: false, + isInventoryItem: false, }; } diff --git a/module/data/item/consumable.mjs b/module/data/item/consumable.mjs index 6c8df798..cb8a13b5 100644 --- a/module/data/item/consumable.mjs +++ b/module/data/item/consumable.mjs @@ -8,7 +8,8 @@ export default class DHConsumable extends BaseDataItem { label: 'TYPES.Item.consumable', type: 'consumable', hasDescription: true, - isQuantifiable: true + isQuantifiable: true, + isInventoryItem: true, }); } diff --git a/module/data/item/miscellaneous.mjs b/module/data/item/miscellaneous.mjs index d7687dc7..529cf9a9 100644 --- a/module/data/item/miscellaneous.mjs +++ b/module/data/item/miscellaneous.mjs @@ -8,7 +8,8 @@ export default class DHMiscellaneous extends BaseDataItem { label: 'TYPES.Item.miscellaneous', type: 'miscellaneous', hasDescription: true, - isQuantifiable: true + isQuantifiable: true, + isInventoryItem: true, }); } diff --git a/module/data/item/weapon.mjs b/module/data/item/weapon.mjs index e7551a21..005f08af 100644 --- a/module/data/item/weapon.mjs +++ b/module/data/item/weapon.mjs @@ -12,10 +12,8 @@ export default class DHWeapon extends BaseDataItem { type: 'weapon', hasDescription: true, isQuantifiable: true, - embedded: { - feature: 'featureTest' - }, - hasInitialAction: true + isInventoryItem: true, + hasInitialAction: true, }); } diff --git a/module/documents/_module.mjs b/module/documents/_module.mjs index 03237ee5..e6099009 100644 --- a/module/documents/_module.mjs +++ b/module/documents/_module.mjs @@ -1,4 +1,4 @@ export { default as DhpActor } from './actor.mjs'; -export { default as DhpItem } from './item.mjs'; +export { default as DHItem } from './item.mjs'; export { default as DhpCombat } from './combat.mjs'; export { default as DhActiveEffect } from './activeEffect.mjs'; diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index c7099b07..350c39a1 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -17,14 +17,6 @@ export default class DhpActor extends Actor { this.updateSource({ prototypeToken }); } - prepareData() { - super.prepareData(); - } - - async _preUpdate(changed, options, user) { - super._preUpdate(changed, options, user); - } - async updateLevel(newLevel) { if (this.type !== 'character' || newLevel === this.system.levelData.level.changed) return; diff --git a/module/documents/item.mjs b/module/documents/item.mjs index 195b9c27..45b9df8e 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -1,14 +1,8 @@ -export default class DhpItem extends Item { - /** @inheritdoc */ - getEmbeddedDocument(embeddedName, id, { invalid = false, strict = false } = {}) { - const systemEmbeds = this.system.constructor.metadata.embedded ?? {}; - if (embeddedName in systemEmbeds) { - const path = `system.${systemEmbeds[embeddedName]}`; - return foundry.utils.getProperty(this, path).get(id) ?? null; - } - return super.getEmbeddedDocument(embeddedName, id, { invalid, strict }); - } - +/** + * Override and extend the basic Item implementation. + * @extends {foundry.documents.Item} + */ +export default class DHItem extends foundry.documents.Item { /** @inheritDoc */ prepareEmbeddedDocuments() { super.prepareEmbeddedDocuments(); @@ -35,75 +29,59 @@ export default class DhpItem extends Item { return data; } - isInventoryItem() { - return ['weapon', 'armor', 'miscellaneous', 'consumable'].includes(this.type); + /** + * Determine if this item is classified as an inventory item based on its metadata. + * @returns {boolean} Returns `true` if the item is an inventory item. + */ + get isInventoryItem() { + return this.system.constructor.metadata.isInventoryItem ?? false; } - static async createDialog(data = {}, { parent = null, pack = null, ...options } = {}) { - const documentName = this.metadata.name; - const types = game.documentTypes[documentName].filter(t => t !== CONST.BASE_DOCUMENT_TYPE); - let collection; - if (!parent) { - if (pack) collection = game.packs.get(pack); - else collection = game.collections.get(documentName); - } - const folders = collection?._formatFolderSelectOptions() ?? []; - const label = game.i18n.localize(this.metadata.label); - const title = game.i18n.format('DOCUMENT.Create', { type: label }); - const typeObjects = types.reduce((obj, t) => { - const label = CONFIG[documentName]?.typeLabels?.[t] ?? t; - obj[t] = { value: t, label: game.i18n.has(label) ? game.i18n.localize(label) : t }; - return obj; - }, {}); + /** @inheritdoc */ + static async createDialog(data = {}, createOptions = {}, options = {}) { + const { folders, types, template, context = {}, ...dialogOptions } = options; - // Render the document creation form - const html = await foundry.applications.handlebars.renderTemplate( - 'systems/daggerheart/templates/sidebar/documentCreate.hbs', - { - folders, - name: data.name || game.i18n.format('DOCUMENT.New', { type: label }), - folder: data.folder, - hasFolders: folders.length >= 1, - type: data.type || CONFIG[documentName]?.defaultType || typeObjects.armor, - types: { - Items: [typeObjects.armor, typeObjects.weapon, typeObjects.consumable, typeObjects.miscellaneous], - Character: [ - typeObjects.class, - typeObjects.subclass, - typeObjects.ancestry, - typeObjects.community, - typeObjects.feature, - typeObjects.domainCard - ] - }, - hasTypes: types.length > 1 + if (types?.length === 0) { + throw new Error('The array of sub-types to restrict to must not be empty.'); + } + + const documentTypes = this.TYPES.filter(type => type !== 'base' && (!types || types.includes(type))).map( + type => { + const labelKey = CONFIG.Item?.typeLabels?.[type]; + const label = labelKey && game.i18n.has(labelKey) ? game.i18n.localize(labelKey) : type; + + const isInventoryItem = CONFIG.Item.dataModels[type]?.metadata?.isInventoryItem; + const group = + isInventoryItem === true + ? 'Inventory Items' + : isInventoryItem === false + ? 'Character Items' + : 'Other'; + + return { value: type, label, group }; } ); - // Render the confirmation dialog window - return Dialog.prompt({ - title: title, - content: html, - label: title, - callback: html => { - const form = html[0].querySelector('form'); - const fd = new FormDataExtended(form); - foundry.utils.mergeObject(data, fd.object, { inplace: true }); - if (!data.folder) delete data.folder; - if (types.length === 1) data.type = types[0]; - if (!data.name?.trim()) data.name = this.defaultName(); - return this.create(data, { parent, pack, renderSheet: true }); - }, - rejectClose: false, - options + if (!documentTypes.length) { + throw new Error('No document types were permitted to be created.'); + } + + const sortedTypes = documentTypes.sort((a, b) => a.label.localeCompare(b.label, game.i18n.lang)); + + return await super.createDialog(data, createOptions, { + folders, + types, + template, + context: { types: sortedTypes, ...context }, + ...dialogOptions }); } async selectActionDialog() { const content = await foundry.applications.handlebars.renderTemplate( - 'systems/daggerheart/templates/views/actionSelect.hbs', - { actions: this.system.actions } - ), + 'systems/daggerheart/templates/views/actionSelect.hbs', + { actions: this.system.actions } + ), title = 'Select Action', type = 'div', data = {}; @@ -142,8 +120,8 @@ export default class DhpItem extends Item { 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'), + ? game.i18n.localize('DAGGERHEART.Chat.FoundationCard.CommunityTitle') + : game.i18n.localize('DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle'), origin: origin, img: this.img, name: this.name, diff --git a/styles/daggerheart.css b/styles/daggerheart.css index cecf313c..4dbf6ac4 100755 --- a/styles/daggerheart.css +++ b/styles/daggerheart.css @@ -4080,6 +4080,10 @@ div.daggerheart.views.multiclass { .application.sheet.daggerheart.actor.dh-style.character .tab.inventory .search-section .search-bar input:placeholder { color: light-dark(#18162e50, #efe6d850); } +.application.sheet.daggerheart.actor.dh-style.character .tab.inventory .search-section .search-bar input::-webkit-search-cancel-button { + -webkit-appearance: none; + display: none; +} .application.sheet.daggerheart.actor.dh-style.character .tab.inventory .search-section .search-bar .icon { align-content: center; height: 32px; diff --git a/styles/less/actors/character/inventory.less b/styles/less/actors/character/inventory.less index a6caf22b..c1583046 100644 --- a/styles/less/actors/character/inventory.less +++ b/styles/less/actors/character/inventory.less @@ -1,65 +1,70 @@ -@import '../../utils/colors.less'; -@import '../../utils/fonts.less'; - -.application.sheet.daggerheart.actor.dh-style.character { - .tab.inventory { - .search-section { - display: flex; - gap: 10px; - align-items: center; - - .search-bar { - position: relative; - color: light-dark(@dark-blue-50, @beige-50); - width: 100%; - padding-top: 5px; - - input { - border-radius: 50px; - font-family: @font-body; - background: light-dark(@dark-blue-10, @golden-10); - border: none; - outline: 2px solid transparent; - transition: all 0.3s ease; - padding: 0 20px; - - &:hover { - outline: 2px solid light-dark(@dark, @golden); - } - - &:placeholder { - color: light-dark(@dark-blue-50, @beige-50); - } - } - - .icon { - align-content: center; - height: 32px; - position: absolute; - right: 20px; - font-size: 16px; - z-index: 1; - color: light-dark(@dark-blue-50, @beige-50); - } - } - } - - .items-section { - display: flex; - flex-direction: column; - gap: 10px; - overflow-y: auto; - mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%); - padding: 20px 0; - height: 80%; - - scrollbar-width: thin; - scrollbar-color: light-dark(@dark-blue, @golden) transparent; - } - - .currency-section { - display: flex; - gap: 10px; - } - } -} +@import '../../utils/colors.less'; +@import '../../utils/fonts.less'; + +.application.sheet.daggerheart.actor.dh-style.character { + .tab.inventory { + .search-section { + display: flex; + gap: 10px; + align-items: center; + + .search-bar { + position: relative; + color: light-dark(@dark-blue-50, @beige-50); + width: 100%; + padding-top: 5px; + + input { + border-radius: 50px; + font-family: @font-body; + background: light-dark(@dark-blue-10, @golden-10); + border: none; + outline: 2px solid transparent; + transition: all 0.3s ease; + padding: 0 20px; + + &:hover { + outline: 2px solid light-dark(@dark, @golden); + } + + &:placeholder { + color: light-dark(@dark-blue-50, @beige-50); + } + + &::-webkit-search-cancel-button { + -webkit-appearance: none; + display: none; + } + } + + .icon { + align-content: center; + height: 32px; + position: absolute; + right: 20px; + font-size: 16px; + z-index: 1; + color: light-dark(@dark-blue-50, @beige-50); + } + } + } + + .items-section { + display: flex; + flex-direction: column; + gap: 10px; + overflow-y: auto; + mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%); + padding: 20px 0; + height: 80%; + + scrollbar-width: thin; + scrollbar-color: light-dark(@dark-blue, @golden) transparent; + } + + .currency-section { + display: flex; + gap: 10px; + } + } +} diff --git a/templates/sheets/actors/character/inventory.hbs b/templates/sheets/actors/character/inventory.hbs index 22b32d3f..3f4b98be 100644 --- a/templates/sheets/actors/character/inventory.hbs +++ b/templates/sheets/actors/character/inventory.hbs @@ -8,7 +8,7 @@
- +
diff --git a/templates/sheets/actors/character/loadout.hbs b/templates/sheets/actors/character/loadout.hbs index e80aaa80..de63323c 100644 --- a/templates/sheets/actors/character/loadout.hbs +++ b/templates/sheets/actors/character/loadout.hbs @@ -8,7 +8,7 @@
- +
\ No newline at end of file diff --git a/templates/views/rollSelection.hbs b/templates/views/rollSelection.hbs index 3a9cf786..c3728ccc 100644 --- a/templates/views/rollSelection.hbs +++ b/templates/views/rollSelection.hbs @@ -2,11 +2,12 @@ {{#if @root.hasRoll}}
+ {{#unless @root.isLite}}
{{#each experiences}} - {{#if description}} + {{#if name}}
- {{description}} + {{name}} +{{value}}
{{/if}} @@ -16,6 +17,10 @@
+ {{/unless}} +
+ +
{{!-- {{#if (not isNpc)}} --}} {{!--