diff --git a/daggerheart.mjs b/daggerheart.mjs index 7a2ac93f..37efbef6 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -61,6 +61,7 @@ CONFIG.Token.hudClass = applications.hud.DHTokenHUD; CONFIG.ui.combat = applications.ui.DhCombatTracker; CONFIG.ui.chat = applications.ui.DhChatLog; +CONFIG.ui.effectsDisplay = applications.ui.DhEffectsDisplay; CONFIG.ui.hotbar = applications.ui.DhHotbar; CONFIG.ui.sidebar = applications.sidebar.DhSidebar; CONFIG.ui.actors = applications.sidebar.DhActorDirectory; @@ -168,6 +169,9 @@ Hooks.on('ready', async () => { ui.countdowns.render({ force: true }); } + ui.effectsDisplay = new CONFIG.ui.effectsDisplay(); + ui.effectsDisplay.render({ force: true }); + if (!(ui.compendiumBrowser instanceof applications.ui.ItemBrowser)) ui.compendiumBrowser = new applications.ui.ItemBrowser(); diff --git a/lang/en.json b/lang/en.json index 47bb62bb..92ff62e8 100755 --- a/lang/en.json +++ b/lang/en.json @@ -2064,6 +2064,7 @@ "basics": "Basics", "bonus": "Bonus", "burden": "Burden", + "condition": "Condition", "continue": "Continue", "criticalSuccess": "Critical Success", "criticalShort": "Critical", @@ -2617,6 +2618,10 @@ "decreasingLoop": "Decreasing Looping", "increasingLoop": "Increasing Looping" }, + "EffectsDisplay": { + "removeThing": "[Right Click] Remove {thing}", + "appliedBy": "Applied By: {by}" + }, "ItemBrowser": { "title": "Daggerheart Compendium Browser", "hint": "Select a Folder in sidebar to start browsing through the compendium", diff --git a/module/applications/dialogs/d20RollDialog.mjs b/module/applications/dialogs/d20RollDialog.mjs index 2534a2b8..f46125d8 100644 --- a/module/applications/dialogs/d20RollDialog.mjs +++ b/module/applications/dialogs/d20RollDialog.mjs @@ -197,7 +197,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio this.config.actionType = this.reactionOverride ? CONFIG.DH.ITEM.actionTypes.reaction.id : this.config.actionType === CONFIG.DH.ITEM.actionTypes.reaction.id - ? null + ? CONFIG.DH.ITEM.actionTypes.action.id : this.config.actionType; this.render(); } diff --git a/module/applications/hud/tokenHUD.mjs b/module/applications/hud/tokenHUD.mjs index 5fa40a4c..f90c26be 100644 --- a/module/applications/hud/tokenHUD.mjs +++ b/module/applications/hud/tokenHUD.mjs @@ -21,7 +21,6 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD { async _prepareContext(options) { const context = await super._prepareContext(options); - context.partyOnCanvas = this.actor.type === 'party' && this.actor.system.partyMembers.some(member => member.getActiveTokens().length > 0); @@ -31,6 +30,7 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD { context.canToggleCombat = DHTokenHUD.#nonCombatTypes.includes(this.actor.type) ? false : context.canToggleCombat; + context.systemStatusEffects = Object.keys(context.statusEffects).reduce((acc, key) => { const effect = context.statusEffects[key]; if (effect.systemEffect) { @@ -193,16 +193,18 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD { } // Update the status of effects which are active for the token actor - const activeEffects = this.actor?.effects || []; + const activeEffects = this.actor?.getActiveEffects() || []; for (const effect of activeEffects) { for (const statusId of effect.statuses) { const status = choices[statusId]; + status.instances = 1 + (status.instances ?? 0); + status.locked = status.locked || effect.condition || status.instances > 1; if (!status) continue; if (status._id) { if (status._id !== effect.id) continue; } status.isActive = true; - if (effect.getFlag('core', 'overlay')) status.isOverlay = true; + if (effect.getFlag?.('core', 'overlay')) status.isOverlay = true; } } diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index c4962b18..7da49eb7 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -717,6 +717,7 @@ export default class CharacterSheet extends DHBaseActorSheet { }; const result = await this.document.diceRoll({ ...config, + actionType: 'action', headerTitle: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${this.actor.name}`, title: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { ability: abilityLabel diff --git a/module/applications/sheets/api/base-actor.mjs b/module/applications/sheets/api/base-actor.mjs index e11d841d..348ffa99 100644 --- a/module/applications/sheets/api/base-actor.mjs +++ b/module/applications/sheets/api/base-actor.mjs @@ -271,7 +271,7 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) { cancel = true; } } else { - await originActor.deleteEmbeddedDocuments('Item', [data.originId], { render: false }); + await originActor.deleteEmbeddedDocuments('Item', [data.originId]); const createData = dropDocument.toObject(); await this.document.createEmbeddedDocuments('Item', [createData]); } diff --git a/module/applications/ui/_module.mjs b/module/applications/ui/_module.mjs index 35a58566..d5f31906 100644 --- a/module/applications/ui/_module.mjs +++ b/module/applications/ui/_module.mjs @@ -2,6 +2,7 @@ export { default as CountdownEdit } from './countdownEdit.mjs'; export { default as DhCountdowns } from './countdowns.mjs'; export { default as DhChatLog } from './chatLog.mjs'; export { default as DhCombatTracker } from './combatTracker.mjs'; +export { default as DhEffectsDisplay } from './effectsDisplay.mjs'; export { default as DhFearTracker } from './fearTracker.mjs'; export { default as DhHotbar } from './hotbar.mjs'; export { ItemBrowser } from './itemBrowser.mjs'; diff --git a/module/applications/ui/countdowns.mjs b/module/applications/ui/countdowns.mjs index d35f2eb8..96315b17 100644 --- a/module/applications/ui/countdowns.mjs +++ b/module/applications/ui/countdowns.mjs @@ -14,7 +14,6 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application constructor(options = {}) { super(options); - this.sidebarCollapsed = true; this.setupHooks(); } @@ -98,11 +97,10 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application async _prepareContext(options) { const context = await super._prepareContext(options); context.isGM = game.user.isGM; - context.sidebarCollapsed = this.sidebarCollapsed; + context.iconOnly = game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownMode) === CONFIG.DH.GENERAL.countdownAppMode.iconOnly; - const setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns); context.countdowns = this.#getCountdowns().reduce((acc, { key, countdown, ownership }) => { const playersWithAccess = game.users.reduce((acc, user) => { diff --git a/module/applications/ui/effectsDisplay.mjs b/module/applications/ui/effectsDisplay.mjs new file mode 100644 index 00000000..7f90e30b --- /dev/null +++ b/module/applications/ui/effectsDisplay.mjs @@ -0,0 +1,117 @@ +import { RefreshType } from '../../systemRegistration/socket.mjs'; + +const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; + +/** + * A UI element which displays the Active Effects on a selected token. + * + * @extends ApplicationV2 + * @mixes HandlebarsApplication + */ + +export default class DhEffectsDisplay extends HandlebarsApplicationMixin(ApplicationV2) { + constructor(options = {}) { + super(options); + + this.setupHooks(); + } + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + id: 'effects-display', + tag: 'div', + classes: ['daggerheart', 'dh-style', 'effects-display'], + window: { + frame: false, + positioned: false, + resizable: false, + minimizable: false + }, + actions: {} + }; + + /** @override */ + static PARTS = { + resources: { + root: true, + template: 'systems/daggerheart/templates/ui/effects-display.hbs' + } + }; + + get element() { + return document.body.querySelector('.daggerheart.dh-style.effects-display'); + } + + get hidden() { + return this.element.classList.contains('hidden'); + } + + _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)); + }); + } + } + + /** @override */ + async _prepareContext(options) { + const context = await super._prepareContext(options); + context.effects = DhEffectsDisplay.getTokenEffects(); + + return context; + } + + static getTokenEffects = token => { + const actor = token + ? token.actor + : canvas.tokens.controlled.length === 0 + ? !game.user.isGM + ? game.user.character + : null + : canvas.tokens.controlled[0].actor; + return actor?.getActiveEffects() ?? []; + }; + + toggleHidden(token, focused) { + const effects = DhEffectsDisplay.getTokenEffects(focused ? token : null); + this.element.hidden = effects.length === 0; + + Hooks.callAll(CONFIG.DH.HOOKS.effectDisplayToggle, this.element.hidden, token); + + this.render(); + } + + async removeEffect(event) { + const element = event.target.closest('.effect-container'); + const effects = DhEffectsDisplay.getTokenEffects(); + const effect = effects.find(x => x.id === element.id); + await effect.delete(); + this.render(); + } + + setupHooks() { + Hooks.on('controlToken', this.toggleHidden.bind(this)); + Hooks.on(RefreshType.EffectsDisplay, this.toggleHidden.bind(this)); + } + + async close(options) { + /* Opt out of Foundry's standard behavior of closing all application windows marked as UI when Escape is pressed */ + if (options.closeKey) return; + + Hooks.off('controlToken', this.toggleHidden); + Hooks.off(RefreshType.EffectsDisplay, this.toggleHidden); + return super.close(options); + } + + async _onRender(context, options) { + await super._onRender(context, options); + + this.element.hidden = context.effects.length === 0; + if (options?.force) { + document.getElementById('ui-right-column-1')?.appendChild(this.element); + } + } +} diff --git a/module/canvas/placeables/token.mjs b/module/canvas/placeables/token.mjs index 367e7682..64ec3fa9 100644 --- a/module/canvas/placeables/token.mjs +++ b/module/canvas/placeables/token.mjs @@ -10,29 +10,7 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { this.effects.overlay = null; // Categorize effects - const statusMap = new Map(foundry.CONFIG.statusEffects.map(status => [status.id, status])); - const activeEffects = (this.actor ? this.actor.effects.filter(x => !x.disabled) : []).reduce((acc, effect) => { - acc.push(effect); - - const currentStatusActiveEffects = acc.filter( - x => x.statuses.size === 1 && x.name === game.i18n.localize(statusMap.get(x.statuses.first())?.name) - ); - for (var status of effect.statuses) { - if (!currentStatusActiveEffects.find(x => x.statuses.has(status))) { - const statusData = statusMap.get(status); - if (statusData) { - acc.push({ - name: game.i18n.localize(statusData.name), - statuses: [status], - img: statusData.icon ?? statusData.img, - tint: effect.tint - }); - } - } - } - - return acc; - }, []); + const activeEffects = this.actor?.getActiveEffects() ?? []; const overlayEffect = activeEffects.findLast(e => e.img && e.getFlag?.('core', 'overlay')); // Draw effects diff --git a/module/config/_module.mjs b/module/config/_module.mjs index 288cd6aa..ef26b958 100644 --- a/module/config/_module.mjs +++ b/module/config/_module.mjs @@ -5,6 +5,7 @@ export * as effectConfig from './effectConfig.mjs'; export * as encounterConfig from './encounterConfig.mjs'; export * as flagsConfig from './flagsConfig.mjs'; export * as generalConfig from './generalConfig.mjs'; +export * as hooksConfig from './hooksConfig.mjs'; export * as itemConfig from './itemConfig.mjs'; export * as settingsConfig from './settingsConfig.mjs'; export * as systemConfig from './system.mjs'; diff --git a/module/config/hooksConfig.mjs b/module/config/hooksConfig.mjs new file mode 100644 index 00000000..d316c4d4 --- /dev/null +++ b/module/config/hooksConfig.mjs @@ -0,0 +1,5 @@ +const hooksConfig = { + effectDisplayToggle: 'DHEffectDisplayToggle' +}; + +export default hooksConfig; diff --git a/module/config/system.mjs b/module/config/system.mjs index a055319b..ac15b1d9 100644 --- a/module/config/system.mjs +++ b/module/config/system.mjs @@ -7,6 +7,7 @@ import * as SETTINGS from './settingsConfig.mjs'; import * as EFFECTS from './effectConfig.mjs'; import * as ACTIONS from './actionConfig.mjs'; import * as FLAGS from './flagsConfig.mjs'; +import HOOKS from './hooksConfig.mjs'; import * as ITEMBROWSER from './itemBrowserConfig.mjs'; export const SYSTEM_ID = 'daggerheart'; @@ -22,5 +23,6 @@ export const SYSTEM = { EFFECTS, ACTIONS, FLAGS, + HOOKS, ITEMBROWSER }; diff --git a/module/documents/activeEffect.mjs b/module/documents/activeEffect.mjs index 1724ec13..fcf1d590 100644 --- a/module/documents/activeEffect.mjs +++ b/module/documents/activeEffect.mjs @@ -1,4 +1,5 @@ import { itemAbleRollParse } from '../helpers/utils.mjs'; +import { RefreshType, socketEvent } from '../systemRegistration/socket.mjs'; export default class DhActiveEffect extends foundry.documents.ActiveEffect { /* -------------------------------------------- */ @@ -85,6 +86,20 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { await super._preCreate(data, options, user); } + /** @inheritdoc */ + _onCreate(data, options, userId) { + super._onCreate(data, options, userId); + + Hooks.callAll(RefreshType.EffectsDisplay); + } + + /** @inheritdoc */ + _onDelete(data, options, userId) { + super._onDelete(data, options, userId); + + Hooks.callAll(RefreshType.EffectsDisplay); + } + /* -------------------------------------------- */ /* Methods */ /* -------------------------------------------- */ diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 9a4e3a8a..82d413d1 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -844,4 +844,37 @@ export default class DhpActor extends Actor { if (this.system._getTags) tags.push(...this.system._getTags()); return tags; } + + /** Get active effects */ + getActiveEffects() { + const statusMap = new Map(foundry.CONFIG.statusEffects.map(status => [status.id, status])); + return this.effects + .filter(x => !x.disabled) + .reduce((acc, effect) => { + acc.push(effect); + + const currentStatusActiveEffects = acc.filter( + x => x.statuses.size === 1 && x.name === game.i18n.localize(statusMap.get(x.statuses.first()).name) + ); + + for (var status of effect.statuses) { + if (!currentStatusActiveEffects.find(x => x.statuses.has(status))) { + const statusData = statusMap.get(status); + if (statusData) { + acc.push({ + condition: status, + appliedBy: game.i18n.localize(effect.name), + name: game.i18n.localize(statusData.name), + statuses: new Set([status]), + img: statusData.icon ?? statusData.img, + description: game.i18n.localize(statusData.description), + tint: effect.tint + }); + } + } + } + + return acc; + }, []); + } } diff --git a/module/documents/tooltipManager.mjs b/module/documents/tooltipManager.mjs index 95b68d50..bd82dda3 100644 --- a/module/documents/tooltipManager.mjs +++ b/module/documents/tooltipManager.mjs @@ -2,6 +2,7 @@ import { AdversaryBPPerEncounter, BaseBPPerEncounter } from '../config/encounter export default class DhTooltipManager extends foundry.helpers.interaction.TooltipManager { #wide = false; + #bordered = false; async activate(element, options = {}) { const { TextEditor } = foundry.applications.ux; @@ -23,6 +24,41 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti this.#wide = false; } + if (element.dataset.tooltip === '#effect-display#') { + this.#bordered = true; + let effect = {}; + if (element.dataset.uuid) { + const effectData = (await foundry.utils.fromUuid(element.dataset.uuid)).toObject(); + effect = { + ...effectData, + name: game.i18n.localize(effectData.name), + description: game.i18n.localize(effectData.description ?? effectData.parent.system.description) + }; + } else { + const conditions = CONFIG.DH.GENERAL.conditions(); + const condition = conditions[element.dataset.condition]; + effect = { + ...condition, + name: game.i18n.localize(condition.name), + description: game.i18n.localize(condition.description), + appliedBy: element.dataset.appliedBy, + isLockedCondition: true + }; + } + + html = await foundry.applications.handlebars.renderTemplate( + `systems/daggerheart/templates/ui/tooltip/effect-display.hbs`, + { + effect + } + ); + + this.tooltip.innerHTML = html; + options.direction = this._determineItemTooltipDirection(element); + } else { + this.#bordered = false; + } + if (element.dataset.tooltip?.startsWith('#item#')) { const itemUuid = element.dataset.tooltip.slice(6); const item = await foundry.utils.fromUuid(itemUuid); @@ -132,6 +168,14 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti super.activate(element, { ...options, html: html }); } + _setStyle(position = {}) { + super._setStyle(position); + + if (this.#bordered) { + this.tooltip.classList.add('bordered-tooltip'); + } + } + _determineItemTooltipDirection(element, prefered = this.constructor.TOOLTIP_DIRECTIONS.LEFT) { const pos = element.getBoundingClientRect(); const dirs = this.constructor.TOOLTIP_DIRECTIONS; @@ -212,6 +256,7 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti return clone; } + /** Get HTML for Battlepoints tooltip */ async getBattlepointHTML(combatId) { const combat = game.combats.get(combatId); diff --git a/module/systemRegistration/socket.mjs b/module/systemRegistration/socket.mjs index ac61238f..27bf48c5 100644 --- a/module/systemRegistration/socket.mjs +++ b/module/systemRegistration/socket.mjs @@ -36,7 +36,8 @@ export const GMUpdateEvent = { export const RefreshType = { Countdown: 'DhCoundownRefresh', - TagTeamRoll: 'DhTagTeamRollRefresh' + TagTeamRoll: 'DhTagTeamRollRefresh', + EffectsDisplay: 'DhEffectsDisplayRefresh' }; export const registerSocketHooks = () => { diff --git a/styles/less/hud/token-hud/token-hud.less b/styles/less/hud/token-hud/token-hud.less index ec67b524..ac269172 100644 --- a/styles/less/hud/token-hud/token-hud.less +++ b/styles/less/hud/token-hud/token-hud.less @@ -52,6 +52,15 @@ align-items: center; justify-content: center; } + + .effect-locked { + position: absolute; + bottom: 2px; + right: 2px; + font-size: 12px; + color: @golden; + filter: drop-shadow(0 0 3px black); + } } } } diff --git a/styles/less/ui/countdown/countdown.less b/styles/less/ui/countdown/countdown.less index 829a59b5..47f06eb7 100644 --- a/styles/less/ui/countdown/countdown.less +++ b/styles/less/ui/countdown/countdown.less @@ -12,18 +12,23 @@ } .daggerheart.dh-style.countdowns { - position: initial; + position: relative; border: 0; border-radius: 4px; box-shadow: none; width: 300px; pointer-events: all; align-self: flex-end; + transition: 0.3s right ease-in-out; .window-title { font-family: @font-body; } + #ui-right:has(#effects-display .effect-container) & { + right: 62px; + } + &.icon-only { width: 180px; min-width: 180px; diff --git a/styles/less/ui/effects-display/sheet.less b/styles/less/ui/effects-display/sheet.less new file mode 100644 index 00000000..1331b094 --- /dev/null +++ b/styles/less/ui/effects-display/sheet.less @@ -0,0 +1,40 @@ +.daggerheart.dh-style.effects-display { + position: absolute; + right: 0; + width: 46px; + max-height: 600px; + overflow: hidden; + border: 0; + + .window-content { + > div { + height: 100%; + } + } + + .effects-display-container { + display: flex; + flex-direction: column; + gap: 4px; + + .effect-container { + position: relative; + pointer-events: all; + border: 1px solid light-dark(@dark-blue, @golden); + border-radius: 3px; + + img { + border-radius: 3px; + } + + .effect-locked { + position: absolute; + bottom: 4px; + right: 4px; + font-size: 16px; + color: @golden; + filter: drop-shadow(0 0 3px black); + } + } + } +} diff --git a/styles/less/ui/index.less b/styles/less/ui/index.less index 743d16ae..7f9ada25 100644 --- a/styles/less/ui/index.less +++ b/styles/less/ui/index.less @@ -31,3 +31,5 @@ @import './sidebar/daggerheartMenu.less'; @import './scene-config/scene-config.less'; + +@import './effects-display/sheet.less'; diff --git a/styles/less/ui/sidebar/tabs.less b/styles/less/ui/sidebar/tabs.less index e220a228..e9de2924 100644 --- a/styles/less/ui/sidebar/tabs.less +++ b/styles/less/ui/sidebar/tabs.less @@ -4,12 +4,18 @@ } } -#interface #ui-right #sidebar { - menu li button { - img { - width: 22px; - max-width: unset; - filter: @beige-filter; +#interface #ui-right { + #ui-right-column-1 { + position: relative; + } + + #sidebar { + menu li button { + img { + width: 22px; + max-width: unset; + filter: @beige-filter; + } } } } @@ -25,4 +31,4 @@ font-size: var(--font-size-12); } } -} \ No newline at end of file +} diff --git a/styles/less/utils/colors.less b/styles/less/utils/colors.less index 6fcf6db2..d582f294 100755 --- a/styles/less/utils/colors.less +++ b/styles/less/utils/colors.less @@ -28,6 +28,8 @@ @dark-golden-40: #2b1d0340; @dark-golden-80: #2b1d0380; +@rustic-brown-80: #4c340780; + @red: #e54e4e; @red-10: #e54e4e10; @red-40: #e54e4e40; diff --git a/styles/less/ux/index.less b/styles/less/ux/index.less index 2108856a..dd0492da 100644 --- a/styles/less/ux/index.less +++ b/styles/less/ux/index.less @@ -1,3 +1,4 @@ @import './tooltip/tooltip.less'; @import './tooltip/battlepoints.less'; +@import './tooltip/bordered-tooltip.less'; @import './autocomplete/autocomplete.less'; diff --git a/styles/less/ux/tooltip/bordered-tooltip.less b/styles/less/ux/tooltip/bordered-tooltip.less new file mode 100644 index 00000000..a4779d71 --- /dev/null +++ b/styles/less/ux/tooltip/bordered-tooltip.less @@ -0,0 +1,44 @@ +#tooltip.bordered-tooltip { + border: 1px solid @golden; + background-image: url('../assets/parchments/dh-parchment-dark.png'); + + .daggerheart.dh-style.tooltip { + display: flex; + flex-direction: column; + text-align: start; + width: 100%; + gap: 5px; + padding: 0px; + border-radius: 3px; + + .tooltip-header { + display: flex; + flex-direction: column; + text-align: start; + padding: 5px; + gap: 0px; + + h2 { + display: flex; + justify-content: start; + font-size: var(--font-size-20); + color: @golden; + font-weight: 700; + margin: 0; + padding: 0; + } + + .subtitle { + font-size: 12px; + } + } + + .close-hint { + border-radius: 3px; + padding: 3px; + background: @rustic-brown-80; + color: @golden; + font-size: 12px; + } + } +} diff --git a/templates/hud/tokenHUD.hbs b/templates/hud/tokenHUD.hbs index aaf2f5f9..09259d4a 100644 --- a/templates/hud/tokenHUD.hbs +++ b/templates/hud/tokenHUD.hbs @@ -46,17 +46,21 @@
{{#each systemStatusEffects as |status|}} -
- +
+ {{#if status.disabled}} / {{/if}} + {{#if status.locked}}{{/if}}
{{/each}} {{#if genericStatusEffects}} {{#each genericStatusEffects as |status|}} - +
+ + {{#if status.locked}}{{/if}} +
{{/each}} {{/if}}
diff --git a/templates/ui/effects-display.hbs b/templates/ui/effects-display.hbs new file mode 100644 index 00000000..da37d8eb --- /dev/null +++ b/templates/ui/effects-display.hbs @@ -0,0 +1,14 @@ +
+
+ {{#each effects as | effect |}} + + + + + {{#if effect.condition}}{{/if}} + + {{/each}} +
+
\ No newline at end of file diff --git a/templates/ui/tooltip/effect-display.hbs b/templates/ui/tooltip/effect-display.hbs new file mode 100644 index 00000000..5ca4fec2 --- /dev/null +++ b/templates/ui/tooltip/effect-display.hbs @@ -0,0 +1,24 @@ +
+
+

{{effect.name}}

+ {{#if effect.appliedBy}} +

{{localize "DAGGERHEART.UI.EffectsDisplay.appliedBy" by=effect.appliedBy}}

+ {{/if}} +
+ + {{#if effect.description}} +
+ {{{effect.description}}} +
+ {{else if effect.parent.system.description}} +
+ {{{effect.parent.system.description}}} +
+ {{/if}} + + {{#unless effect.isLockedCondition}} +

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

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