diff --git a/lang/en.json b/lang/en.json index cd395b60..40317f8c 100755 --- a/lang/en.json +++ b/lang/en.json @@ -293,6 +293,7 @@ "usedMarks": "Used Marks" }, "DeathMove": { + "selectMove": "Select Move", "takeMove": "Take Death Move", "title": "{actor} - Death Move" }, diff --git a/module/applications/dialogs/deathMove.mjs b/module/applications/dialogs/deathMove.mjs index 735c3c18..093d9680 100644 --- a/module/applications/dialogs/deathMove.mjs +++ b/module/applications/dialogs/deathMove.mjs @@ -13,8 +13,9 @@ export default class DhpDeathMove extends HandlebarsApplicationMixin(Application } static DEFAULT_OPTIONS = { - classes: ['daggerheart', 'views', 'death-move'], - position: { width: 800, height: 'auto' }, + classes: ['daggerheart', 'dh-style', 'dialog', 'views', 'death-move'], + position: { width: 'auto', height: 'auto' }, + window: { icon: 'fa-solid fa-skull' }, actions: { selectMove: this.selectMove, takeMove: this.takeMove @@ -32,6 +33,7 @@ export default class DhpDeathMove extends HandlebarsApplicationMixin(Application const context = await super._prepareContext(_options); context.selectedMove = this.selectedMove; context.options = CONFIG.DH.GENERAL.deathMoves; + context.title = game.i18n.localize('DAGGERHEART.APPLICATIONS.DeathMove.takeMove'); return context; } diff --git a/module/applications/hud/tokenHUD.mjs b/module/applications/hud/tokenHUD.mjs index 572b03f9..5c29260b 100644 --- a/module/applications/hud/tokenHUD.mjs +++ b/module/applications/hud/tokenHUD.mjs @@ -66,12 +66,9 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD { if (!status) continue; if (status._id) { if (status._id !== effect.id) continue; - } else { - if (effect.statuses.size !== 1) continue; } status.isActive = true; if (effect.getFlag('core', 'overlay')) status.isOverlay = true; - break; } } diff --git a/module/applications/sheets-configs/activeEffectConfig.mjs b/module/applications/sheets-configs/activeEffectConfig.mjs index 087b5b08..88edf9d6 100644 --- a/module/applications/sheets-configs/activeEffectConfig.mjs +++ b/module/applications/sheets-configs/activeEffectConfig.mjs @@ -99,7 +99,17 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac async _preparePartContext(partId, context) { const partContext = await super._preparePartContext(partId, context); switch (partId) { - case 'changes': + case 'details': + const useGeneric = game.settings.get( + CONFIG.DH.id, + CONFIG.DH.SETTINGS.gameSettings.appearance + ).showGenericStatusEffects; + if (!useGeneric) { + partContext.statuses = Object.values(CONFIG.DH.GENERAL.conditions).map(status => ({ + value: status.id, + label: game.i18n.localize(status.name) + })); + } break; } diff --git a/module/canvas/placeables/token.mjs b/module/canvas/placeables/token.mjs index 967df0f8..dd6f089e 100644 --- a/module/canvas/placeables/token.mjs +++ b/module/canvas/placeables/token.mjs @@ -10,8 +10,28 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { this.effects.overlay = null; // Categorize effects - const activeEffects = this.actor ? Array.from(this.actor.effects).filter(x => !x.disabled) : []; - const overlayEffect = activeEffects.findLast(e => e.img && e.getFlag('core', 'overlay')); + 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.includes(status))) { + const statusData = statusMap.get(status); + acc.push({ + name: game.i18n.localize(statusData.name), + statuses: [status], + img: statusData.icon, + tint: effect.tint + }); + } + } + + return acc; + }, []); + const overlayEffect = activeEffects.findLast(e => e.img && e.getFlag?.('core', 'overlay')); // Draw effects const promises = []; diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index 6781dc83..7e44cad7 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -322,18 +322,21 @@ export const deathMoves = { id: 'avoidDeath', name: 'DAGGERHEART.CONFIG.DeathMoves.avoidDeath.name', img: 'icons/magic/time/hourglass-yellow-green.webp', + icon: 'fa-person-running', description: 'DAGGERHEART.CONFIG.DeathMoves.avoidDeath.description' }, riskItAll: { id: 'riskItAll', name: 'DAGGERHEART.CONFIG.DeathMoves.riskItAll.name', img: 'icons/sundries/gaming/dice-pair-white-green.webp', + icon: 'fa-dice', description: 'DAGGERHEART.CONFIG.DeathMoves.riskItAll.description' }, blazeOfGlory: { id: 'blazeOfGlory', name: 'DAGGERHEART.CONFIG.DeathMoves.blazeOfGlory.name', img: 'icons/magic/life/heart-cross-strong-flame-purple-orange.webp', + icon: 'fa-burst', description: 'DAGGERHEART.CONFIG.DeathMoves.blazeOfGlory.description' } }; diff --git a/module/documents/activeEffect.mjs b/module/documents/activeEffect.mjs index 3c45929b..5d45e2e1 100644 --- a/module/documents/activeEffect.mjs +++ b/module/documents/activeEffect.mjs @@ -41,6 +41,14 @@ export default class DhActiveEffect extends ActiveEffect { }); } + get localizedStatuses() { + const statusMap = new Map(foundry.CONFIG.statusEffects.map(status => [status.id, status.name])); + return this.statuses.map(x => ({ + key: x, + name: game.i18n.localize(statusMap.get(x)) + })); + } + async _preCreate(data, options, user) { const update = {}; if (!data.img) { diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 7c5825e8..ec464ddb 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -388,6 +388,41 @@ export default class DhpActor extends Actor { return this.system.difficulty ?? 10; } + /** @inheritDoc */ + async toggleStatusEffect(statusId, { active, overlay = false } = {}) { + const status = CONFIG.statusEffects.find(e => e.id === statusId); + if (!status) throw new Error(`Invalid status ID "${statusId}" provided to Actor#toggleStatusEffect`); + const existing = []; + + // Find the effect with the static _id of the status effect + if (status._id) { + const effect = this.effects.get(status._id); + if (effect) existing.push(effect.id); + } + + // If no static _id, find all effects that have this status + else { + for (const effect of this.effects) { + if (effect.statuses.has(status.id)) existing.push(effect.id); + } + } + + // Remove the existing effects unless the status effect is forced active + if (existing.length) { + if (active) return true; + await this.deleteEmbeddedDocuments('ActiveEffect', existing); + return false; + } + + // Create a new effect unless the status effect is forced inactive + if (!active && active !== undefined) return; + + const ActiveEffect = getDocumentClass('ActiveEffect'); + const effect = await ActiveEffect.fromStatusEffect(statusId); + if (overlay) effect.updateSource({ 'flags.core.overlay': true }); + return ActiveEffect.implementation.create(effect, { parent: this, keepId: true }); + } + getRollData() { const rollData = super.getRollData(); rollData.system = this.system.getRollData(); @@ -508,16 +543,16 @@ export default class DhpActor extends Actor { Object.entries(healings).forEach(([key, healing]) => { healing.parts.forEach(part => { const update = updates.find(u => u.key === key); - if (update) - update.value += part.total; + if (update) update.value += part.total; else updates.push({ value: part.total, key }); }); }); updates.forEach( u => - (u.value = - !(u.key === 'fear' || this.system?.resources?.[u.key]?.isReversed === false) ? u.value * -1 : u.value) + (u.value = !(u.key === 'fear' || this.system?.resources?.[u.key]?.isReversed === false) + ? u.value * -1 + : u.value) ); await this.modifyResource(updates); @@ -564,7 +599,7 @@ export default class DhpActor extends Actor { } } }); - + Object.keys(updates).forEach(async key => { const u = updates[key]; if (key === 'items') { diff --git a/module/documents/tooltipManager.mjs b/module/documents/tooltipManager.mjs index f685c8a6..974f5596 100644 --- a/module/documents/tooltipManager.mjs +++ b/module/documents/tooltipManager.mjs @@ -87,6 +87,26 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti this.tooltip.innerHTML = html; } } + + const deathMove = element.dataset.tooltip?.startsWith('#deathMove#'); + if (deathMove) { + const name = element.dataset.deathName; + const img = element.dataset.deathImg; + const description = element.dataset.deathDescription; + + html = await foundry.applications.handlebars.renderTemplate( + `systems/daggerheart/templates/ui/tooltip/death-move.hbs`, + { + move: { name: name, img: img, description: description } + } + ); + + this.tooltip.innerHTML = html; + options.direction = this._determineItemTooltipDirection( + element, + this.constructor.TOOLTIP_DIRECTIONS.RIGHT + ); + } } super.activate(element, { ...options, html: html }); diff --git a/styles/less/dialog/actions/action-list.less b/styles/less/dialog/actions/action-list.less index 4011d124..6a899ca7 100644 --- a/styles/less/dialog/actions/action-list.less +++ b/styles/less/dialog/actions/action-list.less @@ -1,4 +1,5 @@ @import '../../utils/fonts.less'; +@import '../../utils/colors.less'; .application.daggerheart.dh-style { .actions-list, @@ -36,7 +37,8 @@ .action-item { &:hover { - background-color: rgba(255, 255, 255, 0.05); + background-color: light-dark(@soft-shadow, @soft-white-shadow); + cursor: pointer; } padding: 5px; border-radius: 5px; @@ -47,7 +49,6 @@ align-items: center; gap: 10px; font-family: @font-body; - cursor: pointer; flex: 1; i { text-align: center; diff --git a/styles/less/dialog/death-move/death-move-container.less b/styles/less/dialog/death-move/death-move-container.less new file mode 100644 index 00000000..d5982131 --- /dev/null +++ b/styles/less/dialog/death-move/death-move-container.less @@ -0,0 +1,57 @@ +@import '../../utils/spacing.less'; +@import '../../utils/colors.less'; +@import '../../utils/fonts.less'; + +.daggerheart.dh-style.dialog.death-move { + .death-move-container { + display: flex; + flex-direction: column; + gap: 5px; + + .moves-list { + .move-item { + display: flex; + align-items: center; + gap: 5px; + + &:hover { + background-color: light-dark(@soft-shadow, @soft-white-shadow); + cursor: pointer; + } + padding: 5px; + border-radius: 5px; + transition: background-color 0.3s ease-in-out; + + .label { + display: flex; + align-items: center; + gap: 10px; + font-family: @font-body; + cursor: pointer; + flex: 1; + i { + text-align: center; + width: 30px; + } + } + + input[type='radio'] { + margin-left: auto; + } + } + } + } + + footer { + margin-top: 8px; + display: flex; + gap: 8px; + + button { + flex: 1; + height: 40px; + font-family: @font-body; + font-weight: 600; + } + } +} diff --git a/styles/less/dialog/downtime/downtime-container.less b/styles/less/dialog/downtime/downtime-container.less index 0f803d9b..6a520d4b 100644 --- a/styles/less/dialog/downtime/downtime-container.less +++ b/styles/less/dialog/downtime/downtime-container.less @@ -1,5 +1,6 @@ @import '../../utils/spacing.less'; @import '../../utils/colors.less'; +@import '../../utils/fonts.less'; .theme-light .daggerheart.dh-style.views.downtime { .downtime-container .activity-container .activity-selected-marker { @@ -69,7 +70,9 @@ button { flex: 1; - font-family: 'Montserrat', sans-serif; + height: 40px; + font-family: @font-body; + font-weight: 600; } } } diff --git a/styles/less/dialog/index.less b/styles/less/dialog/index.less index 66fd981d..496d09e9 100644 --- a/styles/less/dialog/index.less +++ b/styles/less/dialog/index.less @@ -12,6 +12,8 @@ @import './downtime/downtime-container.less'; +@import './death-move/death-move-container.less'; + @import './beastform/sheet.less'; @import './character-creation/creation-action-footer.less'; diff --git a/styles/less/utils/colors.less b/styles/less/utils/colors.less index 622480a7..033a42cb 100755 --- a/styles/less/utils/colors.less +++ b/styles/less/utils/colors.less @@ -38,6 +38,8 @@ @beige-15: #efe6d815; @beige-50: #efe6d850; +@soft-white-shadow: rgba(255, 255, 255, 0.05); + @light-black: rgba(0, 0, 0, 0.3); @soft-shadow: rgba(0, 0, 0, 0.05); diff --git a/templates/dialogs/deathMove.hbs b/templates/dialogs/deathMove.hbs index 1747a340..d2307900 100644 --- a/templates/dialogs/deathMove.hbs +++ b/templates/dialogs/deathMove.hbs @@ -1,19 +1,22 @@