From 8fc26495c13addeeabd192ab5b22b558ccb94598 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Mon, 14 Jul 2025 00:14:32 +0200 Subject: [PATCH] Fixed Feature spellcasting modifier --- .../dialogs/resourceDiceDialog.mjs | 20 +++++++--------- .../applications/sheets/actors/character.mjs | 7 +----- module/applications/sheets/items/feature.mjs | 1 - module/config/generalConfig.mjs | 2 -- module/data/action/baseAction.mjs | 1 - module/data/item/base.mjs | 2 +- module/data/item/feature.mjs | 24 ++++++++++++++++++- module/documents/activeEffect.mjs | 8 +++---- module/helpers/handlebarsHelper.mjs | 8 +++++-- module/helpers/utils.mjs | 12 ++++++++++ templates/dialogs/dice-roll/resourceDice.hbs | 4 ++-- .../sheets/global/partials/item-resource.hbs | 2 +- 12 files changed, 57 insertions(+), 34 deletions(-) diff --git a/module/applications/dialogs/resourceDiceDialog.mjs b/module/applications/dialogs/resourceDiceDialog.mjs index 122b7422..c296c803 100644 --- a/module/applications/dialogs/resourceDiceDialog.mjs +++ b/module/applications/dialogs/resourceDiceDialog.mjs @@ -1,14 +1,12 @@ const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; export default class ResourceDiceDialog extends HandlebarsApplicationMixin(ApplicationV2) { - constructor(name, recovery, actor, resource, options = {}) { + constructor(item, actor, options = {}) { super(options); - this.name = name; - this.recovery = recovery; + this.item = item; this.actor = actor; - this.resource = resource; - this.diceStates = foundry.utils.deepClone(resource.diceStates); + this.diceStates = foundry.utils.deepClone(item.system.resource.diceStates); } static DEFAULT_OPTIONS = { @@ -37,16 +35,14 @@ export default class ResourceDiceDialog extends HandlebarsApplicationMixin(Appli }; get title() { - return game.i18n.format('DAGGERHEART.APPLICATIONS.ResourceDice.title', { name: this.name }); + return game.i18n.format('DAGGERHEART.APPLICATIONS.ResourceDice.title', { name: this.item.name }); } async _prepareContext(_options) { const context = await super._prepareContext(_options); - context.name = this.name; - context.recovery = game.i18n.localize(CONFIG.DH.GENERAL.refreshTypes[this.recovery].label); - context.resource = this.resource; - context.diceStates = this.diceStates; + context.item = this.item; context.actor = this.actor; + context.diceStates = this.diceStates; return context; } @@ -90,9 +86,9 @@ export default class ResourceDiceDialog extends HandlebarsApplicationMixin(Appli this.close(); } - static async create(name, recovery, actor, resource, options = {}) { + static async create(item, actor, options = {}) { return new Promise(resolve => { - const app = new this(name, recovery, actor, resource, options); + const app = new this(item, actor, options); app.addEventListener('close', () => resolve(app.rollValues), { once: true }); app.render({ force: true }); }); diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index cdd1e13f..ab59d231 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -697,12 +697,7 @@ export default class CharacterSheet extends DHBaseActorSheet { const item = this.getItem(event); if (!item) return; - const rollValues = await game.system.api.applications.dialogs.ResourceDiceDialog.create( - item.name, - item.system.resource.recovery, - this.document, - item.system.resource - ); + const rollValues = await game.system.api.applications.dialogs.ResourceDiceDialog.create(item, this.document); if (!rollValues) return; await item.update({ diff --git a/module/applications/sheets/items/feature.mjs b/module/applications/sheets/items/feature.mjs index f7f47c88..ca375fc7 100644 --- a/module/applications/sheets/items/feature.mjs +++ b/module/applications/sheets/items/feature.mjs @@ -68,7 +68,6 @@ export default class FeatureSheet extends DHBaseItemSheet { } ), title = game.i18n.localize('DAGGERHEART.CONFIG.SelectAction.selectType'); - console.log(this.document); return foundry.applications.api.DialogV2.prompt({ window: { title }, diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index 56c618e7..4216f631 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -371,8 +371,6 @@ export const abilityCosts = { label: 'Fear', group: 'TYPES.Actor.adversary' } - // ...featureTokenTypes, - // ...featureDiceTypes }; export const countdownTypes = { diff --git a/module/data/action/baseAction.mjs b/module/data/action/baseAction.mjs index 22968190..6fdadfe2 100644 --- a/module/data/action/baseAction.mjs +++ b/module/data/action/baseAction.mjs @@ -1,7 +1,6 @@ import { DHActionDiceData, DHActionRollData, DHDamageField } from './actionDice.mjs'; import DhpActor from '../../documents/actor.mjs'; import D20RollDialog from '../../applications/dialogs/d20RollDialog.mjs'; -import { getResources } from '../../helpers/utils.mjs'; const fields = foundry.data.fields; diff --git a/module/data/item/base.mjs b/module/data/item/base.mjs index eee3e071..e99c85c3 100644 --- a/module/data/item/base.mjs +++ b/module/data/item/base.mjs @@ -124,7 +124,7 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { ...feature, system: { ...feature.system, - type: this.parent.type, + originItemType: this.parent.type, originId: data._id, identifier: feature.identifier } diff --git a/module/data/item/feature.mjs b/module/data/item/feature.mjs index b401bb18..061772c8 100644 --- a/module/data/item/feature.mjs +++ b/module/data/item/feature.mjs @@ -17,10 +17,32 @@ export default class DHFeature extends BaseDataItem { const fields = foundry.data.fields; return { ...super.defineSchema(), - type: new fields.StringField({ choices: CONFIG.DH.ITEM.featureTypes, nullable: true, initial: null }), + originItemType: new fields.StringField({ + choices: CONFIG.DH.ITEM.featureTypes, + nullable: true, + initial: null + }), originId: new fields.StringField({ nullable: true, initial: null }), identifier: new fields.StringField(), actions: new fields.ArrayField(new ActionField()) }; } + + get spellcastingModifier() { + let traitValue = 0; + if (this.actor && this.originId && ['class', 'subclass'].includes(this.originItemType)) { + if (this.originItemType === 'subclass') { + traitValue = + this.actor.system.traits[this.actor.items.get(this.originId).system.spellcastingTrait]?.value ?? 0; + } else { + const subclass = + this.actor.system.multiclass.value?.id === this.originId + ? this.actor.system.multiclass.subclass + : this.actor.system.class.subclass; + traitValue = this.actor.system.traits[subclass.system.spellcastingTrait]?.value ?? 0; + } + } + + return traitValue; + } } diff --git a/module/documents/activeEffect.mjs b/module/documents/activeEffect.mjs index 45b782de..aa1a5b0d 100644 --- a/module/documents/activeEffect.mjs +++ b/module/documents/activeEffect.mjs @@ -1,3 +1,5 @@ +import { itemAbleRollParse } from '../helpers/utils.mjs'; + export default class DhActiveEffect extends ActiveEffect { get isSuppressed() { // If this is a copied effect from an attachment, never suppress it @@ -53,11 +55,7 @@ export default class DhActiveEffect extends ActiveEffect { } static applyField(model, change, field) { - const isItemTarget = change.value.toLowerCase().startsWith('item.'); - change.value = isItemTarget ? change.value.slice(5) : change.value; - change.value = Roll.safeEval( - Roll.replaceFormulaData(change.value, isItemTarget ? change.effect.parent : model) - ); + change.value = itemAbleRollParse(change.value, model, change.effect.parent); super.applyField(model, change, field); } diff --git a/module/helpers/handlebarsHelper.mjs b/module/helpers/handlebarsHelper.mjs index 0ba61b1c..407f065e 100644 --- a/module/helpers/handlebarsHelper.mjs +++ b/module/helpers/handlebarsHelper.mjs @@ -1,3 +1,5 @@ +import { itemAbleRollParse } from './utils.mjs'; + export default class RegisterHandlebarsHelpers { static registerHelpers() { Handlebars.registerHelper({ @@ -42,7 +44,9 @@ export default class RegisterHandlebarsHelpers { return new Handlebars.SafeString(Array.from(symbols).map(symbol => ``)); } - static rollParsed(value, actor) { - return Roll.replaceFormulaData(value, actor); + static rollParsed(value, actor, item, numerical) { + const isNumerical = typeof numerical === 'boolean' ? numerical : false; + const result = itemAbleRollParse(value, actor, item); + return isNumerical && !result ? 0 : result; } } diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index 7622e090..1e694aad 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -299,3 +299,15 @@ export const updateActorTokens = async (actor, update) => { } } }; + +export const itemAbleRollParse = (value, actor, item) => { + if (!value) return value; + + const isItemTarget = value.toLowerCase().startsWith('item.'); + const slicedValue = isItemTarget ? value.slice(5) : value; + try { + return Roll.safeEval(Roll.replaceFormulaData(slicedValue, isItemTarget ? item : actor)); + } catch (_) { + return ''; + } +}; diff --git a/templates/dialogs/dice-roll/resourceDice.hbs b/templates/dialogs/dice-roll/resourceDice.hbs index 342dd5a0..1063b66a 100644 --- a/templates/dialogs/dice-roll/resourceDice.hbs +++ b/templates/dialogs/dice-roll/resourceDice.hbs @@ -1,10 +1,10 @@
- {{#times (rollParsed resource.max actor)}} + {{#times (rollParsed item.resource.max actor item numerical=true)}} {{#with (ifThen (lookup ../diceStates this) (lookup ../diceStates this) this) as | state |}}
- +
{{/with}} {{/times}} diff --git a/templates/sheets/global/partials/item-resource.hbs b/templates/sheets/global/partials/item-resource.hbs index 0123dfd9..9b92dea0 100644 --- a/templates/sheets/global/partials/item-resource.hbs +++ b/templates/sheets/global/partials/item-resource.hbs @@ -5,7 +5,7 @@
{{else}}
- {{#times (rollParsed item.system.resource.max item.parent)}} + {{#times (rollParsed item.system.resource.max item.parent item numerical=true)}} {{#with (ifThen (lookup ../item.system.resource.diceStates this) (lookup ../item.system.resource.diceStates this) this) as | state |}}