diff --git a/lang/en.json b/lang/en.json index cf96ee3c..47697fa8 100755 --- a/lang/en.json +++ b/lang/en.json @@ -153,7 +153,8 @@ "Config": { "rangeDependence": { "title": "Range Dependence" - } + }, + "stacking": { "title": "Stacking" } }, "RangeDependance": { "hint": "Settings for an optional distance at which this effect should activate", @@ -2987,6 +2988,8 @@ }, "EffectsDisplay": { "removeThing": "[Right Click] Remove {thing}", + "increaseStacks": "[Left Click] Increment Stacks", + "decreaseStacks": "[Right Click] Decrement Stacks", "appliedBy": "Applied By: {by}" }, "ItemBrowser": { diff --git a/module/applications/sheets-configs/activeEffectConfig.mjs b/module/applications/sheets-configs/activeEffectConfig.mjs index 9f970e1d..834a57a8 100644 --- a/module/applications/sheets-configs/activeEffectConfig.mjs +++ b/module/applications/sheets-configs/activeEffectConfig.mjs @@ -151,6 +151,10 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac }); }); + htmlElement + .querySelector('.stacking-change-checkbox') + ?.addEventListener('change', this.stackingChangeToggle.bind(this)); + htmlElement .querySelector('.armor-change-checkbox') ?.addEventListener('change', this.armorChangeToggle.bind(this)); @@ -209,6 +213,16 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac return partContext; } + stackingChangeToggle(event) { + const stackingFields = this.document.system.schema.fields.stacking.fields; + const systemData = { + stacking: event.target.checked + ? { value: stackingFields.value.initial, max: stackingFields.max.initial } + : null + }; + return this.submit({ updateData: { system: systemData } }); + } + armorChangeToggle(event) { if (event.target.checked) { this.addArmorChange(); diff --git a/module/applications/ui/effectsDisplay.mjs b/module/applications/ui/effectsDisplay.mjs index 3bc5e716..035041e1 100644 --- a/module/applications/ui/effectsDisplay.mjs +++ b/module/applications/ui/effectsDisplay.mjs @@ -49,11 +49,9 @@ export default class DhEffectsDisplay extends HandlebarsApplicationMixin(Applica _attachPartListeners(partId, htmlElement, options) { super._attachPartListeners(partId, htmlElement, options); - - if (this.element) { - this.element.querySelectorAll('.effect-container a').forEach(element => { - element.addEventListener('contextmenu', this.removeEffect.bind(this)); - }); + for (const element of this.element?.querySelectorAll('.effect-container a') ?? []) { + element.addEventListener('click', e => this.#onClickEffect(e)); + element.addEventListener('contextmenu', e => this.#onClickEffect(e, -1)); } } @@ -87,11 +85,21 @@ export default class DhEffectsDisplay extends HandlebarsApplicationMixin(Applica this.render(); } - async removeEffect(event) { + async #onClickEffect(event, delta = 1) { const element = event.target.closest('.effect-container'); const effects = DhEffectsDisplay.getTokenEffects(); const effect = effects.find(x => x.id === element.dataset.effectId); - await effect.delete(); + if (!effect || (delta >= 0 && !effect.system.stacking)) { + return; + } + + const maxValue = effect.system.stacking?.max ?? Infinity; + const newValue = Math.clamp((effect.system.stacking?.value ?? 1) + delta, 0, maxValue); + if (newValue > 0) { + await effect.update({ 'system.stacking.value': newValue }); + } else { + await effect.delete(); + } this.render(); } diff --git a/module/applications/ux/contextMenu.mjs b/module/applications/ux/contextMenu.mjs index 9a308667..4e4ec6a4 100644 --- a/module/applications/ux/contextMenu.mjs +++ b/module/applications/ux/contextMenu.mjs @@ -1,56 +1,3 @@ -/** - * @typedef ContextMenuEntry - * @property {string} name The context menu label. Can be localized. - * @property {string} [icon] A string containing an HTML icon element for the menu item. - * @property {string} [classes] Additional CSS classes to apply to this menu item. - * @property {string} [group] An identifier for a group this entry belongs to. - * @property {ContextMenuJQueryCallback} callback The function to call when the menu item is clicked. - * @property {ContextMenuCondition|boolean} [condition] A function to call or boolean value to determine if this entry - * appears in the menu. - */ - -/** - * @callback ContextMenuCondition - * @param {jQuery|HTMLElement} html The element of the context menu entry. - * @returns {boolean} Whether the entry should be rendered in the context menu. - */ - -/** - * @callback ContextMenuCallback - * @param {HTMLElement} target The element that the context menu has been triggered for. - * @returns {unknown} - */ - -/** - * @callback ContextMenuJQueryCallback - * @param {HTMLElement|jQuery} target The element that the context menu has been triggered for. Will - * either be a jQuery object or an HTMLElement instance, depending - * on how the ContextMenu was configured. - * @returns {unknown} - */ - -/** - * @typedef ContextMenuOptions - * @property {string} [eventName="contextmenu"] Optionally override the triggering event which can spawn the menu. If - * the menu is using fixed positioning, this event must be a MouseEvent. - * @property {ContextMenuCallback} [onOpen] A function to call when the context menu is opened. - * @property {ContextMenuCallback} [onClose] A function to call when the context menu is closed. - * @property {boolean} [fixed=false] If true, the context menu is given a fixed position rather than being - * injected into the target. - * @property {boolean} [jQuery=true] If true, callbacks will be passed jQuery objects instead of HTMLElement - * instances. - */ - -/** - * @typedef ContextMenuRenderOptions - * @property {Event} [event] The event that triggered the context menu opening. - * @property {boolean} [animate=true] Animate the context menu opening. - */ - -/** - * A subclass of ContextMenu. - * @extends {foundry.applications.ux.ContextMenu} - */ export default class DHContextMenu extends foundry.applications.ux.ContextMenu { /** * Trigger a context menu event in response to a normal click on a additional options button. diff --git a/module/canvas/placeables/token.mjs b/module/canvas/placeables/token.mjs index 04d1c3c0..35d34f83 100644 --- a/module/canvas/placeables/token.mjs +++ b/module/canvas/placeables/token.mjs @@ -30,8 +30,8 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { if (!effect.img) continue; const promise = effect === overlayEffect - ? this._drawOverlay(effect.img, effect.tint) - : this._drawEffect(effect.img, effect.tint); + ? this._drawOverlay(effect.img, effect.tint, effect) + : this._drawEffect(effect.img, effect.tint, effect); promises.push( promise.then(e => { if (e) e.zIndex = i; @@ -45,6 +45,39 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { this.renderFlags.set({ refreshEffects: true }); } + /**@inheritdoc */ + async _drawEffect(src, tint, effect) { + if (!src) return; + const tex = await foundry.canvas.loadTexture(src, { fallback: 'icons/svg/hazard.svg' }); + const icon = new PIXI.Sprite(tex); + icon.tint = tint ?? 0xffffff; + + if (effect.system.stacking?.value > 1) { + const stackOverlay = new PIXI.Text(effect.system.stacking.value, { + fill: '#f3c267', + stroke: '#000000', + fontSize: 96, + strokeThickness: 4 + }); + const nrDigits = Math.floor(Math.log10(effect.system.stacking.value)) + 1; + stackOverlay.y = -8; + /* This does not account for 1:s being much less wide than other digits. I don't think it's desired however as it makes it look jumpy */ + stackOverlay.x = icon.width - 8 - nrDigits * 56; + stackOverlay.anchor.set(0, 0); + + icon.addChild(stackOverlay); + } + + return this.effects.addChild(icon); + } + + async _drawOverlay(src, tint, effect) { + const icon = await this._drawEffect(src, tint, effect); + if (icon) icon.alpha = 0.8; + this.effects.overlay = icon ?? null; + return icon; + } + /** * Returns the distance from this token to another token object. * This value is corrected to handle alternate token sizes and other grid types diff --git a/module/data/activeEffect/baseEffect.mjs b/module/data/activeEffect/baseEffect.mjs index c00b8cf7..44e7ec0f 100644 --- a/module/data/activeEffect/baseEffect.mjs +++ b/module/data/activeEffect/baseEffect.mjs @@ -80,7 +80,20 @@ export default class BaseEffect extends foundry.data.ActiveEffectTypeDataModel { initial: CONFIG.DH.GENERAL.range.melee.id, label: 'DAGGERHEART.GENERAL.range' }) - }) + }), + stacking: new fields.SchemaField( + { + value: new fields.NumberField({ + initial: 1, + min: 1, + integer: true, + nullable: false, + label: 'DAGGERHEART.GENERAL.value' + }), + max: new fields.NumberField({ integer: true, label: 'DAGGERHEART.GENERAL.max' }) + }, + { nullable: true, initial: null } + ) }; } diff --git a/module/data/fields/action/effectsField.mjs b/module/data/fields/action/effectsField.mjs index 1a003e2b..9a4ffc31 100644 --- a/module/data/fields/action/effectsField.mjs +++ b/module/data/fields/action/effectsField.mjs @@ -106,22 +106,11 @@ export default class EffectsField extends fields.ArrayField { } /** - * Apply an Effect to a target or enable it if already on it + * Apply an Effect to a target * @param {object} effect Effect object containing ActiveEffect UUID * @param {object} actor Actor Document */ static async applyEffect(effect, actor) { - const existingEffect = actor.effects.find(e => e.origin === effect.uuid); - if (existingEffect) { - return effect.update( - foundry.utils.mergeObject({ - ...effect.constructor.getInitialDuration(), - disabled: false - }) - ); - } - - // Otherwise, create a new effect on the target const effectData = foundry.utils.mergeObject({ ...(effect.toObject?.() ?? effect), disabled: false, diff --git a/module/documents/activeEffect.mjs b/module/documents/activeEffect.mjs index 07c68518..4aeba3af 100644 --- a/module/documents/activeEffect.mjs +++ b/module/documents/activeEffect.mjs @@ -108,6 +108,18 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { update.img = 'icons/magic/life/heart-cross-blue.webp'; } + const existingEffect = this.actor.effects.find(x => x.origin === data.origin); + const stacks = Boolean(data.system?.stacking); + if (existingEffect && !stacks) return false; + + if (existingEffect && stacks) { + const incrementedValue = existingEffect.system.stacking.value + 1; + await existingEffect.update({ + 'system.stacking.value': Math.min(incrementedValue, existingEffect.system.stacking.max ?? Infinity) + }); + return false; + } + const statuses = Object.keys(data.statuses ?? {}); const immuneStatuses = statuses.filter( @@ -184,7 +196,10 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { } catch (_) {} } - const evalValue = this.effectSafeEval(itemAbleRollParse(key, parseModel, effect.parent)); + const stackingParsedValue = effect.system.stacking + ? Roll.replaceFormulaData(key, { stacks: effect.system.stacking.value }) + : key; + const evalValue = itemAbleRollParse(stackingParsedValue, parseModel, effect.parent); return evalValue ?? key; } diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 47a9cd31..8105471b 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -122,6 +122,14 @@ export default class DhpActor extends Actor { } } + _onUpdateDescendantDocuments(parent, collection, documents, changes, options, userId) { + if (collection === 'effects') { + ui.effectsDisplay.render(); + } + + super._onUpdateDescendantDocuments(parent, collection, documents, changes, options, userId); + } + async updateLevel(newLevel) { if (!['character', 'companion'].includes(this.type) || newLevel === this.system.levelData.level.changed) return; diff --git a/src/packs/classes/feature_No_Mercy_njj2C3tMDeCHHOoh.json b/src/packs/classes/feature_No_Mercy_njj2C3tMDeCHHOoh.json index b5239242..5b770e5d 100644 --- a/src/packs/classes/feature_No_Mercy_njj2C3tMDeCHHOoh.json +++ b/src/packs/classes/feature_No_Mercy_njj2C3tMDeCHHOoh.json @@ -71,13 +71,17 @@ "changes": [ { "key": "system.bonuses.roll.attack.bonus", - "value": 1, + "type": "add", + "value": "@stacks", "priority": null, - "type": "add" + "phase": "initial" } ], "duration": { "type": "shortRest" + }, + "stacking": { + "max": null } }, "disabled": false, diff --git a/src/packs/classes/feature_Rogue_s_Dodge_hVaaPIjxoextIgSL.json b/src/packs/classes/feature_Rogue_s_Dodge_hVaaPIjxoextIgSL.json index 0f31f491..b886b079 100644 --- a/src/packs/classes/feature_Rogue_s_Dodge_hVaaPIjxoextIgSL.json +++ b/src/packs/classes/feature_Rogue_s_Dodge_hVaaPIjxoextIgSL.json @@ -69,14 +69,18 @@ "changes": [ { "key": "system.evasion", - "value": 2, + "type": "add", + "value": "2 * @stacks", "priority": null, - "type": "add" + "phase": "initial" } ], "duration": { "type": "temporary", "description": "

Until the next time an attack succeeds against you.

" + }, + "stacking": { + "max": null } }, "disabled": false, diff --git a/src/packs/domains/domainCard_Corrosive_Projectile_qJaSNTuDfbPVr8Lb.json b/src/packs/domains/domainCard_Corrosive_Projectile_qJaSNTuDfbPVr8Lb.json index 01d88111..6a039bbf 100644 --- a/src/packs/domains/domainCard_Corrosive_Projectile_qJaSNTuDfbPVr8Lb.json +++ b/src/packs/domains/domainCard_Corrosive_Projectile_qJaSNTuDfbPVr8Lb.json @@ -127,7 +127,7 @@ "sort": 3400000, "effects": [ { - "name": "Corroded (1 stack)", + "name": "Corroded", "img": "icons/magic/acid/dissolve-bone-white.webp", "origin": "Compendium.daggerheart.domains.Item.qJaSNTuDfbPVr8Lb", "transfer": false, @@ -139,27 +139,31 @@ "type": "withinRange", "target": "hostile", "range": "melee" + }, + "changes": [ + { + "key": "system.difficulty", + "type": "add", + "value": "-@stack", + "priority": null, + "phase": "initial" + } + ], + "stacking": { + "max": null + }, + "duration": { + "type": "" } }, - "changes": [ - { - "key": "system.difficulty", - "mode": 2, - "value": "-1", - "priority": null - } - ], "disabled": false, "duration": { - "startTime": null, - "combat": null, - "seconds": null, - "rounds": null, - "turns": null, - "startRound": null, - "startTurn": null + "value": null, + "units": "seconds", + "expiry": null, + "expired": false }, - "description": "

While a target is Corroded, they gain a −1 penalty to their Difficulty for every 2 Stress you spent. This condition can stack.

", + "description": "

While a target is Corroded, they gain a −1 penalty to their Difficulty for every 2 Stress you spent. This condition can stack.

", "tint": "#ffffff", "statuses": [ "corrode" @@ -169,6 +173,16 @@ "_stats": { "compendiumSource": null }, + "start": { + "time": 0, + "combat": null, + "combatant": null, + "initiative": null, + "round": null, + "turn": null + }, + "showIcon": 1, + "folder": null, "_key": "!items.effects!qJaSNTuDfbPVr8Lb.zB95bjSSdVlApQnR" } ], diff --git a/src/packs/domains/domainCard_Rage_Up_GRL0cvs96vrTDckZ.json b/src/packs/domains/domainCard_Rage_Up_GRL0cvs96vrTDckZ.json index 6f8b481d..c3493aea 100644 --- a/src/packs/domains/domainCard_Rage_Up_GRL0cvs96vrTDckZ.json +++ b/src/packs/domains/domainCard_Rage_Up_GRL0cvs96vrTDckZ.json @@ -42,44 +42,8 @@ "type": "self", "amount": null }, - "name": "Mark 1 Stress", - "img": "icons/magic/control/silhouette-aura-energy.webp", - "range": "self" - }, - "fKY9NcYBwCFwMsgV": { - "type": "effect", - "_id": "fKY9NcYBwCFwMsgV", - "systemPath": "actions", - "description": "

You can mark a Stress to gain a bonus to your damage roll equal to twice your Strength.

", - "chatDisplay": true, - "actionType": "action", - "cost": [ - { - "scalable": false, - "key": "stress", - "value": 2, - "step": null, - "consumeOnSuccess": false - } - ], - "uses": { - "value": null, - "max": "", - "recovery": null, - "consumeOnSuccess": false - }, - "effects": [ - { - "_id": "t6SIjQxB6UBUJ98f", - "onSave": false - } - ], - "target": { - "type": "self", - "amount": null - }, - "name": "Mark 2 Stress", - "img": "icons/magic/control/silhouette-aura-energy.webp", + "name": "Mark Stress", + "img": "icons/skills/wounds/injury-face-impact-orange.webp", "range": "self" } }, @@ -94,8 +58,8 @@ "sort": 3400000, "effects": [ { - "name": "Rage Up (1)", - "img": "systems/daggerheart/assets/icons/domains/domain-card/blade.png", + "name": "Rage Up", + "img": "icons/skills/wounds/injury-face-impact-orange.webp", "origin": "Compendium.daggerheart.domains.Item.GRL0cvs96vrTDckZ", "transfer": false, "_id": "bq1MhcmoP6Wo5CXF", @@ -106,33 +70,38 @@ "type": "withinRange", "target": "hostile", "range": "melee" + }, + "changes": [ + { + "key": "system.bonuses.damage.magical.bonus", + "type": "add", + "value": "2*@system.traits.strength.value*@stacks", + "priority": 21, + "phase": "initial" + }, + { + "key": "system.bonuses.damage.physical.bonus", + "type": "add", + "value": "2*@system.traits.strength.value*@stacks", + "priority": 21, + "phase": "initial" + } + ], + "stacking": { + "max": 2 + }, + "duration": { + "type": "" } }, - "changes": [ - { - "key": "system.bonuses.damage.magical.bonus", - "mode": 2, - "value": "2*@system.traits.strength.value", - "priority": 21 - }, - { - "key": "system.bonuses.damage.physical.bonus", - "mode": 2, - "value": "2*@system.traits.strength.value", - "priority": 21 - } - ], "disabled": false, "duration": { - "startTime": null, - "combat": null, - "seconds": null, - "rounds": null, - "turns": null, - "startRound": null, - "startTurn": null + "value": null, + "units": "seconds", + "expiry": null, + "expired": false }, - "description": "", + "description": "

For your next attack you have a bonus to your damage roll equal to twice your Strength.

", "tint": "#ffffff", "statuses": [], "sort": 0, @@ -140,6 +109,16 @@ "_stats": { "compendiumSource": null }, + "start": { + "time": 0, + "combat": null, + "combatant": null, + "initiative": null, + "round": null, + "turn": null + }, + "showIcon": 1, + "folder": null, "_key": "!items.effects!GRL0cvs96vrTDckZ.bq1MhcmoP6Wo5CXF" }, { @@ -155,31 +134,28 @@ "type": "withinRange", "target": "hostile", "range": "melee" - } - }, - "changes": [ - { - "key": "system.bonuses.damage.magical.bonus", - "mode": 2, - "value": "4*@system.traits.strength.value", - "priority": 21 }, - { - "key": "system.bonuses.damage.physical.bonus", - "mode": 2, - "value": "4*@system.traits.strength.value", - "priority": 21 - } - ], + "changes": [ + { + "key": "system.bonuses.damage.magical.bonus", + "value": "4*@system.traits.strength.value", + "priority": 21, + "type": "add" + }, + { + "key": "system.bonuses.damage.physical.bonus", + "value": "4*@system.traits.strength.value", + "priority": 21, + "type": "add" + } + ] + }, "disabled": false, "duration": { - "startTime": null, - "combat": null, - "seconds": null, - "rounds": null, - "turns": null, - "startRound": null, - "startTurn": null + "value": null, + "units": "seconds", + "expiry": null, + "expired": false }, "description": "", "tint": "#ffffff", @@ -189,6 +165,9 @@ "_stats": { "compendiumSource": null }, + "start": null, + "showIcon": 1, + "folder": null, "_key": "!items.effects!GRL0cvs96vrTDckZ.t6SIjQxB6UBUJ98f" } ], diff --git a/styles/less/global/elements.less b/styles/less/global/elements.less index c33557b1..793c8164 100755 --- a/styles/less/global/elements.less +++ b/styles/less/global/elements.less @@ -293,6 +293,20 @@ } } + &.optional, + &.one-column.optional { + padding-top: 0; + padding-bottom: 4px; + min-height: auto; + row-gap: 0; + + legend { + display: flex; + align-items: center; + padding-left: 3px; + } + } + .list-w-img { padding: 5px; label { @@ -469,6 +483,10 @@ &.even { grid-template-columns: 1fr 1fr; } + + &.full-width { + width: 100%; + } } .three-columns { diff --git a/styles/less/sheets/activeEffects/activeEffects.less b/styles/less/sheets/activeEffects/activeEffects.less index 3f6526cb..e4f5c541 100644 --- a/styles/less/sheets/activeEffects/activeEffects.less +++ b/styles/less/sheets/activeEffects/activeEffects.less @@ -33,16 +33,6 @@ } .armor-change-container { - padding-top: 0; - padding-bottom: 4px; - row-gap: 0; - - legend { - display: flex; - align-items: center; - padding-left: 3px; - } - header { padding: 0; left: -0.25rem; // TODO: Find why this header is offset 0.25rem to the right so this can be removed. diff --git a/styles/less/ui/effects-display/sheet.less b/styles/less/ui/effects-display/sheet.less index 1331b094..17d9889f 100644 --- a/styles/less/ui/effects-display/sheet.less +++ b/styles/less/ui/effects-display/sheet.less @@ -35,6 +35,21 @@ color: @golden; filter: drop-shadow(0 0 3px black); } + + .stacking-value { + position: absolute; + top: 4px; + right: 4px; + font-size: 16px; + font-weight: bold; + font-variant-numeric: tabular-nums; + color: @golden; + background: black; + padding: 1px; + border-radius: 6px; + border: 1px solid @golden; + pointer-events: none; + } } } } diff --git a/styles/less/ux/tooltip/bordered-tooltip.less b/styles/less/ux/tooltip/bordered-tooltip.less index b3a5ed29..abec93b7 100644 --- a/styles/less/ux/tooltip/bordered-tooltip.less +++ b/styles/less/ux/tooltip/bordered-tooltip.less @@ -6,6 +6,7 @@ .daggerheart.dh-style.tooltip { display: flex; flex-direction: column; + align-items: start; text-align: start; width: 100%; gap: 5px; @@ -13,6 +14,7 @@ border-radius: 3px; .tooltip-header { + width: 100%; display: flex; flex-direction: column; align-items: center; @@ -35,12 +37,48 @@ } } - .close-hint { - border-radius: 3px; - padding: 3px; - background: @rustic-brown-80; - color: @golden; - font-size: 12px; + .effect-stacks-outer-container { + display: flex; + flex-direction: column; + gap: 4px; + width: 100%; + + .effect-stacks-title { + font-size: var(--font-size-20); + font-weight: bold; + text-align: center; + } + + .effect-stacks-container { + display: flex; + justify-content: space-between; + + .effect-stacks-inner-container { + display: flex; + flex-direction: column; + gap: 2px; + + .effect-stack-title { + font-weight: bold; + } + } + } + } + + .close-hints { + margin-top: 0.5rem; + display: flex; + flex-direction: column; + gap: 4px; + + .close-hint { + border-radius: 3px; + padding: 3px; + background: @rustic-brown-80; + color: @golden; + font-size: 12px; + margin: 0; + } } .duration-container { diff --git a/templates/sheets/activeEffect/changes.hbs b/templates/sheets/activeEffect/changes.hbs index 47a48382..37feb845 100644 --- a/templates/sheets/activeEffect/changes.hbs +++ b/templates/sheets/activeEffect/changes.hbs @@ -14,8 +14,12 @@ {{/each}} -
- {{localize "DAGGERHEART.GENERAL.armor"}} +
+ + {{localize "DAGGERHEART.GENERAL.armor"}} + + + {{#if typedChanges.armor}} {{> "systems/daggerheart/templates/sheets/activeEffect/typeChanges/armorChange.hbs" typedChanges.armor fields=@root.systemFields.changes.element.types.armor.fields}} {{/if}} diff --git a/templates/sheets/activeEffect/settings.hbs b/templates/sheets/activeEffect/settings.hbs index 9443edfb..9307ff65 100644 --- a/templates/sheets/activeEffect/settings.hbs +++ b/templates/sheets/activeEffect/settings.hbs @@ -1,4 +1,18 @@
+
+ + {{localize "DAGGERHEART.ACTIVEEFFECT.Config.stacking.title"}} + + + + {{#if source.system.stacking}} +
+ {{formGroup systemFields.stacking.fields.value value=source.system.stacking.value localize=true }} + {{formGroup systemFields.stacking.fields.max value=source.system.stacking.max localize=true }} +
+ {{/if}} +
+
{{localize "DAGGERHEART.ACTIVEEFFECT.Config.rangeDependence.title"}} diff --git a/templates/ui/effects-display.hbs b/templates/ui/effects-display.hbs index 95c6023c..67c783a6 100644 --- a/templates/ui/effects-display.hbs +++ b/templates/ui/effects-display.hbs @@ -8,6 +8,9 @@ + {{#if (gt effect.system.stacking.value 1)}} + {{effect.system.stacking.value}} + {{/if}} {{#if effect.condition}}{{/if}} {{/each}} diff --git a/templates/ui/tooltip/effect-display.hbs b/templates/ui/tooltip/effect-display.hbs index d37b5147..ebb21be4 100644 --- a/templates/ui/tooltip/effect-display.hbs +++ b/templates/ui/tooltip/effect-display.hbs @@ -17,7 +17,6 @@ {{/if}} {{#if effect.system.duration.type}} -
{{localize "EFFECT.DURATION.Label"}}: @@ -26,9 +25,42 @@
{{/if}} + {{#if effect.system.stacking}} +
+
{{localize "Stacks"}}
+
+
+ {{localize "Current"}} + {{effect.system.stacking.value}} +
+
+ {{localize "Max"}} + {{effect.system.stacking.max}} +
+
+
+ {{/if}} + {{#unless effect.isLockedCondition}} -

- {{localize "DAGGERHEART.UI.EffectsDisplay.removeThing" thing=(localize "DAGGERHEART.GENERAL.Effect.single")}} -

+
+ {{#if effect.system.stacking}} +

+ {{localize "DAGGERHEART.UI.EffectsDisplay.increaseStacks"}} +

+ {{#if (gt effect.system.stacking.value 1)}} +

+ {{localize "DAGGERHEART.UI.EffectsDisplay.decreaseStacks"}} +

+ {{else}} +

+ {{localize "DAGGERHEART.UI.EffectsDisplay.removeThing" thing=(localize "DAGGERHEART.GENERAL.Effect.single")}} +

+ {{/if}} + {{else}} +

+ {{localize "DAGGERHEART.UI.EffectsDisplay.removeThing" thing=(localize "DAGGERHEART.GENERAL.Effect.single")}} +

+ {{/if}} +
{{/unless}}
\ No newline at end of file