From 750282aeec3a260cc7efbd35dd6f955875f88f43 Mon Sep 17 00:00:00 2001 From: Dapoulp <74197441+Dapoulp@users.noreply.github.com> Date: Wed, 2 Jul 2025 21:13:06 +0200 Subject: [PATCH 1/4] Feature/233 234 235 (#246) * #233 #234 #235 + Fixes * Fix reaction roll --- lang/en.json | 4 + .../applications/npcRollSelectionDialog.mjs | 2 + module/applications/roll.mjs | 195 ++++++++++-------- module/applications/rollSelectionDialog.mjs | 2 + .../applications/sheets/actors/adversary.mjs | 2 +- .../applications/adversary-settings.mjs | 1 + module/config/actionConfig.mjs | 15 ++ module/data/action/action.mjs | 7 +- module/data/action/actionDice.mjs | 5 +- module/data/fields/actionField.mjs | 4 +- module/data/item/base.mjs | 5 +- module/dialogs/d20RollDialog.mjs | 20 +- module/dialogs/damageDialog.mjs | 9 +- styles/chat.less | 20 +- styles/daggerheart.css | 14 +- styles/less/global/elements.less | 12 ++ templates/chat/adversary-roll.hbs | 4 +- templates/chat/duality-roll.hbs | 24 +++ .../adversary-settings/attack.hbs | 18 +- templates/views/action.hbs | 2 - templates/views/actionTypes/damage.hbs | 106 +++++----- templates/views/actionTypes/roll.hbs | 3 + templates/views/damageSelection.hbs | 6 +- templates/views/rollSelection.hbs | 67 ++++-- 24 files changed, 355 insertions(+), 192 deletions(-) diff --git a/lang/en.json b/lang/en.json index 4458d9ac..49196f50 100755 --- a/lang/en.json +++ b/lang/en.json @@ -192,6 +192,10 @@ "Full": "Disadvantage", "Short": "Dis" }, + "Neutral": { + "Full": "None", + "Short": "no" + }, "OK": "OK", "Cancel": "Cancel", "Or": "Or", diff --git a/module/applications/npcRollSelectionDialog.mjs b/module/applications/npcRollSelectionDialog.mjs index 7c8290fb..1a56f12a 100644 --- a/module/applications/npcRollSelectionDialog.mjs +++ b/module/applications/npcRollSelectionDialog.mjs @@ -1,3 +1,5 @@ +/** NOT USED ANYMORE - TO BE DELETED **/ + const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; export default class NpcRollSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) { diff --git a/module/applications/roll.mjs b/module/applications/roll.mjs index cb7d0dff..1c89644f 100644 --- a/module/applications/roll.mjs +++ b/module/applications/roll.mjs @@ -8,6 +8,7 @@ import DamageDialog from '../dialogs/damageDialog.mjs'; */ export class DHRoll extends Roll { + baseTerms = []; constructor(formula, data, options) { super(formula, data, options); } @@ -37,6 +38,7 @@ export class DHRoll extends Roll { if (config.dialog.configure !== false) { // Open Roll Dialog const DialogClass = config.dialog?.class ?? this.DefaultDialog; + console.log(roll, config) const configDialog = await DialogClass.configure(roll, config, message); if (!configDialog) return; } @@ -98,9 +100,27 @@ export class DHRoll extends Roll { config.dialog.configure ??= !(config.event.shiftKey || config.event.altKey || config.event.ctrlKey); } + formatModifier(modifier) { + const numTerm = modifier < 0 ? '-' : '+'; + return [ + new foundry.dice.terms.OperatorTerm({ operator: numTerm }), + new foundry.dice.terms.NumericTerm({ number: Math.abs(modifier) }) + ]; + } + + getFaces(faces) { + return Number((faces.startsWith('d') ? faces.replace('d', '') : faces)); + } + constructFormula(config) { - // const formula = Roll.replaceFormulaData(this.options.roll.formula, config.data); this.terms = Roll.parse(this.options.roll.formula, config.data); + + if (this.options.extraFormula) { + this.terms.push( + new foundry.dice.terms.OperatorTerm({ operator: '+' }), + ...this.constructor.parse(this.options.extraFormula, this.options.data) + ); + } return (this._formula = this.constructor.getFormula(this.terms)); } } @@ -112,12 +132,9 @@ export class DualityDie extends foundry.dice.terms.Die { } export class D20Roll extends DHRoll { + constructor(formula, data = {}, options = {}) { super(formula, data, options); - // this.createBaseDice(); - // this.configureModifiers(); - - // this._formula = this.resetFormula(); this.constructFormula(); } @@ -140,7 +157,7 @@ export class D20Roll extends DHRoll { set d20(faces) { if (!(this.terms[0] instanceof foundry.dice.terms.Die)) this.createBaseDice(); - this.terms[0].faces = faces; + this.terms[0].faces = this.getFaces(faces); } get dAdvantage() { @@ -153,11 +170,11 @@ export class D20Roll extends DHRoll { } get hasAdvantage() { - return this.options.advantage === this.constructor.ADV_MODE.ADVANTAGE; + return this.options.roll.advantage === this.constructor.ADV_MODE.ADVANTAGE; } get hasDisadvantage() { - return this.options.advantage === this.constructor.ADV_MODE.DISADVANTAGE; + return this.options.roll.advantage === this.constructor.ADV_MODE.DISADVANTAGE; } static applyKeybindings(config) { @@ -171,18 +188,55 @@ export class D20Roll extends DHRoll { config.dialog.configure ??= !Object.values(keys).some(k => k); // Determine advantage mode - const advantage = config.advantage || keys.advantage; - const disadvantage = config.disadvantage || keys.disadvantage; - if (advantage && !disadvantage) config.advantage = this.ADV_MODE.ADVANTAGE; - else if (!advantage && disadvantage) config.advantage = this.ADV_MODE.DISADVANTAGE; - else config.advantage = this.ADV_MODE.NORMAL; + const advantage = config.roll.advantage === this.ADV_MODE.ADVANTAGE || keys.advantage; + const disadvantage = config.roll.advantage === this.ADV_MODE.DISADVANTAGE || keys.disadvantage; + if (advantage && !disadvantage) config.roll.advantage = this.ADV_MODE.ADVANTAGE; + else if (!advantage && disadvantage) config.roll.advantage = this.ADV_MODE.DISADVANTAGE; + else config.roll.advantage = this.ADV_MODE.NORMAL; + } + + constructFormula(config) { + // this.terms = []; + this.createBaseDice(); + this.configureModifiers(); + this.resetFormula(); + return this._formula; } createBaseDice() { - if (this.terms[0] instanceof foundry.dice.terms.Die) return; + if (this.terms[0] instanceof foundry.dice.terms.Die) { + this.terms = [this.terms[0]]; + return; + } this.terms[0] = new foundry.dice.terms.Die({ faces: 20 }); } + configureModifiers() { + this.applyAdvantage(); + this.applyBaseBonus(); + + this.options.experiences?.forEach(m => { + if (this.options.data.experiences?.[m]) + this.options.roll.modifiers.push({ + label: this.options.data.experiences[m].name, + value: this.options.data.experiences[m].total ?? this.options.data.experiences[m].value + }); + }); + + this.options.roll.modifiers?.forEach(m => { + this.terms.push(...this.formatModifier(m.value)); + }); + + this.baseTerms = foundry.utils.deepClone(this.terms); + + if (this.options.extraFormula) { + this.terms.push( + new foundry.dice.terms.OperatorTerm({ operator: '+' }), + ...this.constructor.parse(this.options.extraFormula, this.options.data) + ); + } + } + applyAdvantage() { this.d20.modifiers.findSplice(m => ['kh', 'kl'].includes(m)); if (!this.hasAdvantage && !this.hasDisadvantage) this.number = 1; @@ -192,47 +246,16 @@ export class D20Roll extends DHRoll { } } - // Trait bonus != Adversary - configureModifiers() { - this.applyAdvantage(); - // this.options.roll.modifiers = []; - this.applyBaseBonus(); - - this.options.experiences?.forEach(m => { - if (this.options.data.experiences?.[m]) - this.options.roll.modifiers.push({ - label: this.options.data.experiences[m].name, - value: this.options.data.experiences[m].total ?? this.options.data.experiences[m].value - }); - }); - this.options.roll.modifiers?.forEach(m => { - this.terms.push(...this.formatModifier(m.value)); - }); - - if (this.options.extraFormula) { - this.terms.push( - new foundry.dice.terms.OperatorTerm({ operator: '+' }), - ...this.constructor.parse(this.options.extraFormula, this.getRollData()) - ); - } - // this.resetFormula(); - } - - constructFormula(config) { - this.terms = []; - this.createBaseDice(); - this.configureModifiers(); - this.resetFormula(); - return this._formula; - } - applyBaseBonus() { - this.options.roll.modifiers = [ + this.options.roll.modifiers = []; + if(!this.options.roll.bonus) return; + this.options.roll.modifiers.push( { label: 'Bonus to Hit', - value: Roll.replaceFormulaData('@attackBonus', this.data) + value: this.options.roll.bonus + // value: Roll.replaceFormulaData('@attackBonus', this.data) } - ]; + ); } static postEvaluate(roll, config = {}) { @@ -242,26 +265,22 @@ export class D20Roll extends DHRoll { const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion; target.hit = this.isCritical || roll.total >= difficulty; }); - } else if (config.roll.difficulty) - config.roll.success = roll.isCritical || roll.total >= config.roll.difficulty; + } else if (config.roll.difficulty) config.roll.success = roll.isCritical || roll.total >= config.roll.difficulty; config.roll.advantage = { - type: config.advantage, + type: config.roll.advantage, dice: roll.dAdvantage?.denomination, value: roll.dAdvantage?.total }; - config.roll.modifierTotal = config.roll.modifiers.reduce((a, c) => a + Number(c.value), 0); - } - - getRollData() { - return this.options.data; - } - - formatModifier(modifier) { - const numTerm = modifier < 0 ? '-' : '+'; - return [ - new foundry.dice.terms.OperatorTerm({ operator: numTerm }), - new foundry.dice.terms.NumericTerm({ number: Math.abs(modifier) }) - ]; + config.roll.extra = roll.dice.filter(d => !roll.baseTerms.includes(d)).map(d => { + return { + dice: d.denomination, + value: d.total + } + }) + config.roll.modifierTotal = 0; + for(let i = 0; i < roll.terms.length; i++) { + if(roll.terms[i] instanceof foundry.dice.terms.NumericTerm && !!roll.terms[i-1] && roll.terms[i-1] instanceof foundry.dice.terms.OperatorTerm) config.roll.modifierTotal += Number(`${roll.terms[i-1].operator}${roll.terms[i].total}`); + } } resetFormula() { @@ -270,6 +289,8 @@ export class D20Roll extends DHRoll { } export class DualityRoll extends D20Roll { + _advantageFaces = 6; + constructor(formula, data = {}, options = {}) { super(formula, data, options); } @@ -287,7 +308,7 @@ export class DualityRoll extends D20Roll { set dHope(faces) { if (!(this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie)) this.createBaseDice(); - this.terms[0].faces = faces; + this.terms[0].faces = this.getFaces(faces); // this.#hopeDice = `d${face}`; } @@ -300,7 +321,7 @@ export class DualityRoll extends D20Roll { set dFear(faces) { if (!(this.dice[1] instanceof CONFIG.Dice.daggerheart.DualityDie)) this.createBaseDice(); - this.dice[1].faces = faces; + this.dice[1].faces = this.getFaces(faces); // this.#fearDice = `d${face}`; } @@ -308,6 +329,14 @@ export class DualityRoll extends D20Roll { return this.dice[2]; } + get advantageFaces() { + return this._advantageFaces; + } + + set advantageFaces(faces) { + this._advantageFaces = this.getFaces(faces); + } + get isCritical() { if (!this.dHope._evaluated || !this.dFear._evaluated) return; return this.dHope.total === this.dFear.total; @@ -337,25 +366,25 @@ export class DualityRoll extends D20Roll { return game.i18n.localize(label); } + updateFormula() { + + } + createBaseDice() { - if ( - this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie && - this.dice[1] instanceof CONFIG.Dice.daggerheart.DualityDie - ) + if (this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie && this.dice[1] instanceof CONFIG.Dice.daggerheart.DualityDie) { + this.terms = [this.terms[0], this.terms[1], this.terms[2]]; return; - if (!(this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie)) - this.terms[0] = new CONFIG.Dice.daggerheart.DualityDie(); + } + this.terms[0] = new CONFIG.Dice.daggerheart.DualityDie(); this.terms[1] = new foundry.dice.terms.OperatorTerm({ operator: '+' }); - if (!(this.dice[2] instanceof CONFIG.Dice.daggerheart.DualityDie)) - this.terms[2] = new CONFIG.Dice.daggerheart.DualityDie(); + this.terms[2] = new CONFIG.Dice.daggerheart.DualityDie(); } applyAdvantage() { - const dieFaces = 6, + const dieFaces = this.advantageFaces, bardRallyFaces = this.hasBarRally, advDie = new foundry.dice.terms.Die({ faces: dieFaces }); - if (this.hasAdvantage || this.hasDisadvantage || bardRallyFaces) - this.terms.push(new foundry.dice.terms.OperatorTerm({ operator: this.hasDisadvantage ? '-' : '+' })); + if (this.hasAdvantage || this.hasDisadvantage || bardRallyFaces) this.terms.push(new foundry.dice.terms.OperatorTerm({ operator: this.hasDisadvantage ? '-' : '+' })); if (bardRallyFaces) { const rallyDie = new foundry.dice.terms.Die({ faces: bardRallyFaces }); if (this.hasAdvantage) { @@ -372,12 +401,14 @@ export class DualityRoll extends D20Roll { } applyBaseBonus() { - this.options.roll.modifiers = [ + this.options.roll.modifiers = []; + if(!this.options.roll.trait) return; + this.options.roll.modifiers.push( { label: `DAGGERHEART.Abilities.${this.options.roll.trait}.name`, value: Roll.replaceFormulaData(`@traits.${this.options.roll.trait}.total`, this.data) } - ]; + ); } static postEvaluate(roll, config = {}) { diff --git a/module/applications/rollSelectionDialog.mjs b/module/applications/rollSelectionDialog.mjs index 0a1972aa..fbc77d2b 100644 --- a/module/applications/rollSelectionDialog.mjs +++ b/module/applications/rollSelectionDialog.mjs @@ -1,3 +1,5 @@ +/** NOT USED ANYMORE - TO BE DELETED **/ + const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; export default class RollSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) { diff --git a/module/applications/sheets/actors/adversary.mjs b/module/applications/sheets/actors/adversary.mjs index a588ba0f..e2f5c978 100644 --- a/module/applications/sheets/actors/adversary.mjs +++ b/module/applications/sheets/actors/adversary.mjs @@ -87,7 +87,7 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) { event: event, title: `${this.actor.name} - Reaction Roll`, roll: { - modifier: null, + // modifier: null, type: 'reaction' }, chatMessage: { diff --git a/module/applications/sheets/applications/adversary-settings.mjs b/module/applications/sheets/applications/adversary-settings.mjs index 2ecdcb60..cc18d7f6 100644 --- a/module/applications/sheets/applications/adversary-settings.mjs +++ b/module/applications/sheets/applications/adversary-settings.mjs @@ -103,6 +103,7 @@ export default class DHAdversarySettings extends HandlebarsApplicationMixin(Appl context.systemFields = this.actor.system.schema.fields; context.systemFields.attack.fields = this.actor.system.attack.schema.fields; context.isNPC = true; + console.log(context) return context; } diff --git a/module/config/actionConfig.mjs b/module/config/actionConfig.mjs index 6506e485..e83040f5 100644 --- a/module/config/actionConfig.mjs +++ b/module/config/actionConfig.mjs @@ -105,3 +105,18 @@ export const diceCompare = { operator: '>' } }; + +export const advandtageState = { + disadvantage: { + label: 'DAGGERHEART.General.Disadvantage.Full', + value: -1 + }, + neutral: { + label: 'DAGGERHEART.General.Neutral.Full', + value: 0 + }, + advantage: { + label: 'DAGGERHEART.General.Advantage.Full', + value: 1 + } +} diff --git a/module/data/action/action.mjs b/module/data/action/action.mjs index af5e061e..33b7280a 100644 --- a/module/data/action/action.mjs +++ b/module/data/action/action.mjs @@ -1,4 +1,3 @@ -import CostSelectionDialog from '../../applications/costSelectionDialog.mjs'; import { DHActionDiceData, DHActionRollData, DHDamageData, DHDamageField } from './actionDice.mjs'; import DhpActor from '../../documents/actor.mjs'; import D20RollDialog from '../../dialogs/d20RollDialog.mjs'; @@ -343,7 +342,9 @@ export class DHBaseAction extends foundry.abstract.DataModel { label: 'Attack', type: this.actionType, difficulty: this.roll?.difficulty, - formula: this.roll.getFormula() + formula: this.roll.getFormula(), + bonus: this.roll.bonus, + advantage: SYSTEM.ACTIONS.advandtageState[this.roll.advState].value }; if (this.roll?.type === 'diceSet') roll.lite = true; @@ -372,7 +373,7 @@ export class DHBaseAction extends foundry.abstract.DataModel { /* ROLL */ get hasRoll() { - return !!this.roll?.type; + return !!this.roll?.type || !!this.roll?.bonus; } /* ROLL */ diff --git a/module/data/action/actionDice.mjs b/module/data/action/actionDice.mjs index 8a6aa12a..adf00461 100644 --- a/module/data/action/actionDice.mjs +++ b/module/data/action/actionDice.mjs @@ -11,7 +11,8 @@ export class DHActionRollData extends foundry.abstract.DataModel { type: new fields.StringField({ nullable: true, initial: null, choices: SYSTEM.GENERAL.rollTypes }), trait: new fields.StringField({ nullable: true, initial: null, choices: SYSTEM.ACTOR.abilities }), difficulty: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }), - bonus: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }), + bonus: new fields.NumberField({ nullable: true, initial: null, integer: true }), + advState: new fields.StringField({ choices: SYSTEM.ACTIONS.advandtageState, initial: 'neutral' }), diceRolling: new fields.SchemaField({ multiplier: new fields.StringField({ choices: SYSTEM.GENERAL.diceSetNumbers, @@ -62,7 +63,7 @@ export class DHActionDiceData extends foundry.abstract.DataModel { label: 'Multiplier' }), flatMultiplier: new fields.NumberField({ nullable: true, initial: 1, label: 'Flat Multiplier' }), - dice: new fields.StringField({ choices: SYSTEM.GENERAL.diceTypes, initial: 'd6', label: 'Formula' }), + dice: new fields.StringField({ choices: SYSTEM.GENERAL.diceTypes, initial: 'd6', label: 'Dice' }), bonus: new fields.NumberField({ nullable: true, initial: null, label: 'Bonus' }), custom: new fields.SchemaField({ enabled: new fields.BooleanField({ label: 'Custom Formula' }), diff --git a/module/data/fields/actionField.mjs b/module/data/fields/actionField.mjs index da520fd1..3628bbae 100644 --- a/module/data/fields/actionField.mjs +++ b/module/data/fields/actionField.mjs @@ -1,9 +1,9 @@ -import { actionsTypes } from '../action/_module.mjs'; +// import { actionsTypes } from '../action/_module.mjs'; // Temporary Solution export default class ActionField extends foundry.data.fields.ObjectField { getModel(value) { - return actionsTypes[value.type] ?? actionsTypes.attack; + return game.system.api.models.actionsTypes[value.type] ?? game.system.api.models.actionsTypes.attack; } /* -------------------------------------------- */ diff --git a/module/data/item/base.mjs b/module/data/item/base.mjs index 735c6588..4d41d731 100644 --- a/module/data/item/base.mjs +++ b/module/data/item/base.mjs @@ -1,4 +1,4 @@ -import { actionsTypes } from '../action/_module.mjs'; +// import { actionsTypes } from '../action/_module.mjs'; /** * Describes metadata about the item data model type @@ -60,7 +60,8 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { const actionType = { weapon: 'attack' }[this.constructor.metadata.type], - cls = actionsTypes.attack, + cls = game.system.api.models.actionsTypes[actionType], + // cls = actionsTypes.attack, action = new cls( { _id: foundry.utils.randomID(), diff --git a/module/dialogs/d20RollDialog.mjs b/module/dialogs/d20RollDialog.mjs index 7c4fd06b..b21e79df 100644 --- a/module/dialogs/d20RollDialog.mjs +++ b/module/dialogs/d20RollDialog.mjs @@ -9,7 +9,8 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio this.config.experiences = []; if (config.source?.action) { - this.item = config.data.parent.items.get(config.source.item); + console.log(config) + this.item = config.data.parent.items.get(config.source.item) ?? config.data.parent; this.action = config.data.attack?._id == config.source.action ? config.data.attack @@ -50,15 +51,18 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio }; async _prepareContext(_options) { + console.log(this.config, this.roll) const context = await super._prepareContext(_options); context.hasRoll = !!this.config.roll; + context.roll = this.roll; + context.rollType = this.roll?.constructor.name; context.experiences = Object.keys(this.config.data.experiences).map(id => ({ id, ...this.config.data.experiences[id] })); context.selectedExperiences = this.config.experiences; - context.advantage = this.config.advantage; - /* context.diceOptions = this.diceOptions; */ + context.advantage = this.config.roll?.advantage; + context.diceOptions = SYSTEM.GENERAL.diceTypes; context.canRoll = true; context.isLite = this.config.roll?.lite; if (this.config.costs?.length) { @@ -71,7 +75,9 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio context.uses = this.action.calcUses(this.config.uses); context.canRoll = context.canRoll && this.action.hasUses(context.uses); } + context.extraFormula = this.config.extraFormula; context.formula = this.roll.constructFormula(this.config); + return context; } @@ -81,12 +87,18 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio this.config.costs = foundry.utils.mergeObject(this.config.costs, rest.costs); } if (this.config.uses) this.config.uses = foundry.utils.mergeObject(this.config.uses, rest.uses); + if(rest.roll?.dice) { + Object.entries(rest.roll.dice).forEach(([key, value]) => { + this.roll[key] = value; + }) + } + this.config.extraFormula = rest.extraFormula; this.render(); } static updateIsAdvantage(_, button) { const advantage = Number(button.dataset.advantage); - this.config.advantage = this.config.advantage === advantage ? 0 : advantage; + this.config.roll.advantage = this.config.roll.advantage === advantage ? 0 : advantage; this.render(); } diff --git a/module/dialogs/damageDialog.mjs b/module/dialogs/damageDialog.mjs index b94c2aab..4882475d 100644 --- a/module/dialogs/damageDialog.mjs +++ b/module/dialogs/damageDialog.mjs @@ -37,10 +37,17 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application async _prepareContext(_options) { const context = await super._prepareContext(_options); context.title = this.config.title; - context.formula = this.config.roll.formula; + context.extraFormula = this.config.extraFormula; + context.formula = this.roll.constructFormula(this.config);; return context; } + static updateRollConfiguration(event, _, formData) { + const { ...rest } = foundry.utils.expandObject(formData.object); + this.config.extraFormula = rest.extraFormula; + this.render(); + } + static async submitRoll() { await this.close({ submitted: true }); } diff --git a/styles/chat.less b/styles/chat.less index 77aa892b..c0e45af4 100644 --- a/styles/chat.less +++ b/styles/chat.less @@ -493,16 +493,18 @@ fieldset.daggerheart.chat { align-items: end; gap: 0.25rem; .dice { - .dice-rolls.duality { + .dice-rolls { margin-bottom: 0; - li { - display: flex; - align-items: center; - justify-content: center; - position: relative; - background: unset; - line-height: unset; - font-weight: unset; + &.duality { + li { + display: flex; + align-items: center; + justify-content: center; + position: relative; + background: unset; + line-height: unset; + font-weight: unset; + } } } } diff --git a/styles/daggerheart.css b/styles/daggerheart.css index 062dd5a3..dc9cdabb 100755 --- a/styles/daggerheart.css +++ b/styles/daggerheart.css @@ -1786,7 +1786,7 @@ fieldset.daggerheart.chat .daggerheart.chat { align-items: end; gap: 0.25rem; } -.theme-colorful .chat-message.duality .message-content .dice-result .dice-tooltip .wrapper .tooltip-part .dice .dice-rolls.duality { +.theme-colorful .chat-message.duality .message-content .dice-result .dice-tooltip .wrapper .tooltip-part .dice .dice-rolls { margin-bottom: 0; } .theme-colorful .chat-message.duality .message-content .dice-result .dice-tooltip .wrapper .tooltip-part .dice .dice-rolls.duality li { @@ -5376,6 +5376,18 @@ div.daggerheart.views.multiclass { display: flex; gap: 20px; } +.application.dh-style fieldset.flex.wrap { + flex-wrap: wrap; + gap: 10px 20px; +} +.application.dh-style fieldset.flex .inline-child { + flex: 1; +} +.application.dh-style fieldset.flex .checkbox { + display: flex; + align-items: center; + gap: 20px; +} .application.dh-style fieldset.one-column { display: flex; flex-direction: column; diff --git a/styles/less/global/elements.less b/styles/less/global/elements.less index 9caa12c6..1f6e5988 100755 --- a/styles/less/global/elements.less +++ b/styles/less/global/elements.less @@ -119,6 +119,18 @@ &.flex { display: flex; gap: 20px; + &.wrap { + flex-wrap: wrap; + gap: 10px 20px; + } + .inline-child { + flex: 1; + } + .checkbox { + display: flex; + align-items: center; + gap: 20px; + } } &.one-column { diff --git a/templates/chat/adversary-roll.hbs b/templates/chat/adversary-roll.hbs index 7794d683..0004e586 100644 --- a/templates/chat/adversary-roll.hbs +++ b/templates/chat/adversary-roll.hbs @@ -6,7 +6,7 @@
- {{#each roll.dice}} + {{#each roll.dice as | dice index |}}
{{formula}} {{total}} @@ -17,9 +17,11 @@
  • {{result}}
  • {{/each}} + {{#if (eq index 0)}}
    {{#if (eq ../roll.advantage.type 1)}}{{localize "DAGGERHEART.General.Advantage.Full"}}{{/if}}{{#if (eq ../roll.advantage.type -1)}}{{localize "DAGGERHEART.General.Disadvantage.Full"}}{{/if}}
    + {{/if}}
    {{/each}}
    diff --git a/templates/chat/duality-roll.hbs b/templates/chat/duality-roll.hbs index 65ec1676..9a530649 100644 --- a/templates/chat/duality-roll.hbs +++ b/templates/chat/duality-roll.hbs @@ -82,6 +82,30 @@ {{/if}} + {{#each roll.extra as | extra | }} +
    +
    + + 1{{extra.dice}} + + {{extra.value}} +
    +
    +
      +
    1. +
      +
      +
      + +
      +
      {{extra.value}}
      +
      +
      +
    2. +
    +
    +
    + {{/each}} {{#if roll.modifierTotal}}
    {{#if (gt roll.modifierTotal 0)}}+{{/if}}{{roll.modifierTotal}}
    {{/if}} diff --git a/templates/sheets/applications/adversary-settings/attack.hbs b/templates/sheets/applications/adversary-settings/attack.hbs index cb11d46f..d731e5f6 100644 --- a/templates/sheets/applications/adversary-settings/attack.hbs +++ b/templates/sheets/applications/adversary-settings/attack.hbs @@ -1,22 +1,22 @@
    - {{localize 'DAGGERHEART.General.basics'}} - {{formGroup systemFields.attack.fields.img value=document.img label="Image Path" name="system.attack.img"}} + {{localize "DAGGERHEART.General.basics"}} + {{formGroup systemFields.attack.fields.img value=document.system.attack.img label="Image Path" name="system.attack.img"}} {{formGroup systemFields.attack.fields.name value=document.system.attack.name label="Attack Name" name="system.attack.name"}}
    {{localize "DAGGERHEART.Sheets.Adversary.Attack"}} {{formField systemFields.attack.fields.roll.fields.bonus value=document.system.attack.roll.bonus label="Attack Bonus" name="system.attack.roll.bonus"}} - {{formField systemFields.attack.fields.range value=document.system.attack.range label="Range" name=(concat path "range") localize=true}} + {{formField systemFields.attack.fields.range value=document.system.attack.range label="Range" name="system.attack.range" localize=true}} {{#if systemFields.attack.fields.target.fields}} - {{#if (and document.system.target.type (not (eq document.system.target.type 'self')))}} - {{ formField systemFields.attack.fields.target.fields.amount value=document.system.target.amount label="Amount" name=(concat path "target.amount") }} + {{ formField systemFields.attack.fields.target.fields.type value=document.system.attack.target.type label="Target" name="system.attack.target.type" localize=true }} + {{#if (and document.system.attack.target.type (not (eq document.system.attack.target.type 'self')))}} + {{ formField systemFields.attack.fields.target.fields.amount value=document.system.attack.target.amount label="Amount" name="system.attack.target.amount" }} {{/if}} - {{ formField systemFields.attack.fields.target.fields.type value=document.system.target.type label="Target" name=(concat path "target.type") localize=true }} {{/if}}
    {{> 'systems/daggerheart/templates/views/actionTypes/damage.hbs' fields=systemFields.attack.fields.damage.fields.parts.element.fields source=document.system.attack.damage path="system.attack."}} diff --git a/templates/views/action.hbs b/templates/views/action.hbs index 45373815..9a3a25b4 100644 --- a/templates/views/action.hbs +++ b/templates/views/action.hbs @@ -33,10 +33,8 @@
    - {{#unless isNPC}} {{> 'systems/daggerheart/templates/views/actionTypes/uses.hbs' fields=fields.uses.fields source=source.uses}} {{> 'systems/daggerheart/templates/views/actionTypes/cost.hbs' fields=fields.cost.element.fields source=source.cost}} - {{/unless}} {{#if fields.target}}{{> 'systems/daggerheart/templates/views/actionTypes/range-target.hbs' fields=(object range=fields.range target=fields.target.fields) source=(object target=source.target range=source.range)}}{{/if}}
    diff --git a/templates/views/actionTypes/damage.hbs b/templates/views/actionTypes/damage.hbs index 54fdb6b1..01dc533a 100644 --- a/templates/views/actionTypes/damage.hbs +++ b/templates/views/actionTypes/damage.hbs @@ -1,61 +1,57 @@ -
    - -
    Damage
    -
    -
    - {{#unless @root.isNPC}} -
    - {{#if @root.hasBaseDamage}} -
    - {{formField @root.fields.damage.fields.includeBase value=@root.source.damage.includeBase label="Include Item Damage" name="damage.includeBase" }} -
    - {{/if}} - {{/unless}} - {{#each source.parts as |dmg index|}} - {{#if @root.isNPC}} - {{formField ../fields.value.fields.custom.fields.enabled value=dmg.value.custom.enabled name=(concat ../path "damage.parts." index ".value.custom.enabled")}} - - {{#if dmg.value.custom.enabled}} - {{formField ../fields.value.fields.custom.fields.formula value=dmg.value.custom.formula name=(concat ../path "damage.parts." index ".value.custom.formula") localize=true}} - {{else}} -
    - {{formField ../fields.value.fields.flatMultiplier value=dmg.value.flatMultiplier name=(concat ../path "damage.parts." index ".value.flatMultiplier") label="Multiplier" }} - {{formField ../fields.value.fields.dice value=dmg.value.dice name=(concat ../path "damage.parts." index ".value.dice")}} - {{formField ../fields.value.fields.bonus value=dmg.value.bonus name=(concat ../path "damage.parts." index ".value.bonus") localize=true}} -
    - {{/if}} - {{formField ../fields.type value=dmg.type name=(concat ../path "damage.parts." index ".type") localize=true}} +
    + Damage + {{#unless (eq path 'system.attack.')}} +
    + {{/unless}} + {{#unless @root.isNPC}} + {{#if @root.hasBaseDamage}} +
    + {{formField @root.fields.damage.fields.includeBase value=@root.source.damage.includeBase label="Include Item Damage" name="damage.includeBase" }} +
    + {{/if}} + {{/unless}} + {{#each source.parts as |dmg index|}} + {{#if @root.isNPC}} + {{formField ../fields.value.fields.custom.fields.enabled value=dmg.value.custom.enabled name=(concat ../path "damage.parts." index ".value.custom.enabled") classes="checkbox"}} + + {{#if dmg.value.custom.enabled}} + {{formField ../fields.value.fields.custom.fields.formula value=dmg.value.custom.formula name=(concat ../path "damage.parts." index ".value.custom.formula") localize=true}} {{else}} - {{#with (@root.getRealIndex index) as | realIndex |}} - - {{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base))}} - {{formField ../../fields.resultBased value=dmg.resultBased name=(concat "damage.parts." realIndex ".resultBased") localize=true}} - {{/if}} - {{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base) dmg.resultBased)}} -
    - -
    With Hope
    -
    - {{> formula fields=../../fields.value.fields type=../../fields.type dmg=dmg source=dmg.value target="value" realIndex=realIndex}} -
    -
    - -
    With Fear
    -
    - {{> formula fields=../../fields.valueAlt.fields type=../../fields.type dmg=dmg source=dmg.valueAlt target="valueAlt" realIndex=realIndex}} -
    - {{else}} - {{> formula fields=../../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" realIndex=realIndex}} - {{/if}} - {{formField ../../fields.type value=dmg.type name=(concat "damage.parts." realIndex ".type") localize=true}} - - {{#unless dmg.base}}
    {{/unless}} -
    - {{/with}} + {{formField ../fields.value.fields.flatMultiplier value=dmg.value.flatMultiplier name=(concat ../path "damage.parts." index ".value.flatMultiplier") label="Multiplier" classes="inline-child" }} + {{formField ../fields.value.fields.dice value=dmg.value.dice name=(concat ../path "damage.parts." index ".value.dice") classes="inline-child"}} + {{formField ../fields.value.fields.bonus value=dmg.value.bonus name=(concat ../path "damage.parts." index ".value.bonus") localize=true classes="inline-child"}} {{/if}} - {{/each}} -
    + {{formField ../fields.type value=dmg.type name=(concat ../path "damage.parts." index ".type") localize=true}} + {{else}} + {{#with (@root.getRealIndex index) as | realIndex |}} + + {{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base))}} + {{formField ../../fields.resultBased value=dmg.resultBased name=(concat "damage.parts." realIndex ".resultBased") localize=true}} + {{/if}} + {{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base) dmg.resultBased)}} +
    + +
    With Hope
    +
    + {{> formula fields=../../fields.value.fields type=../../fields.type dmg=dmg source=dmg.value target="value" realIndex=realIndex}} +
    +
    + +
    With Fear
    +
    + {{> formula fields=../../fields.valueAlt.fields type=../../fields.type dmg=dmg source=dmg.valueAlt target="valueAlt" realIndex=realIndex}} +
    + {{else}} + {{> formula fields=../../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" realIndex=realIndex}} + {{/if}} + {{formField ../../fields.type value=dmg.type name=(concat "damage.parts." realIndex ".type") localize=true}} + + {{#unless dmg.base}}
    {{/unless}} +
    + {{/with}} + {{/if}} + {{/each}} {{#*inline "formula"}} diff --git a/templates/views/actionTypes/roll.hbs b/templates/views/actionTypes/roll.hbs index c4a7387c..cfc79670 100644 --- a/templates/views/actionTypes/roll.hbs +++ b/templates/views/actionTypes/roll.hbs @@ -24,5 +24,8 @@
    {{/if}} {{/if}} + {{#unless (eq source.type "diceSet")}} + {{formField fields.advState label= "Advantage State" name="roll.advState" value=source.advState localize=true}} + {{/unless}} \ No newline at end of file diff --git a/templates/views/damageSelection.hbs b/templates/views/damageSelection.hbs index b7c61443..988b852e 100644 --- a/templates/views/damageSelection.hbs +++ b/templates/views/damageSelection.hbs @@ -2,7 +2,11 @@
    - + {{!-- --}} +
    {{@root.formula}}
    +
    +
    +
    {{!-- {{#each bonusDamage as |damage index|}} diff --git a/templates/views/rollSelection.hbs b/templates/views/rollSelection.hbs index c3728ccc..98b6c91b 100644 --- a/templates/views/rollSelection.hbs +++ b/templates/views/rollSelection.hbs @@ -2,25 +2,58 @@ {{#if @root.hasRoll}}
    - {{#unless @root.isLite}} -
    - {{#each experiences}} - {{#if name}} -
    - {{name}} - +{{value}} -
    - {{/if}} - {{/each}} -
    -
    - - -
    - {{/unless}}
    - + {{!-- --}} +
    {{@root.formula}}
    + {{#unless @root.isLite}} +
    + {{#each experiences}} + {{#if name}} +
    + {{name}} + +{{value}} +
    + {{/if}} + {{/each}} +
    +
    + + +
    + {{#if (eq @root.rollType 'D20Roll')}} +
    + +
    + {{/if}} + {{#if (eq @root.rollType 'DualityRoll')}} +
    +
    Hope Dice
    + +
    +
    +
    Fear Dice
    + +
    + {{#if roll.advantage}} +
    +
    Adv/Disadv Dice
    + +
    + {{/if}} + {{/if}} +
    + +
    + {{/unless}} {{!-- {{#if (not isNpc)}} --}} {{!--
    From ee8a48f73d42b32d61952e7af4058c5b594d6bb8 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Wed, 2 Jul 2025 23:21:02 +0200 Subject: [PATCH 2/4] Added DhTooltipManager aswell as placeholder rendering for Armor/Weapon/DomainCard (#245) --- daggerheart.mjs | 1 + module/applications/_module.mjs | 1 + module/applications/tooltipManager.mjs | 16 ++++++++++++++++ .../sheets/global/partials/inventory-item.hbs | 2 +- templates/tooltip/armor.hbs | 5 +++++ templates/tooltip/domainCard.hbs | 5 +++++ templates/tooltip/weapon.hbs | 5 +++++ 7 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 module/applications/tooltipManager.mjs create mode 100644 templates/tooltip/armor.hbs create mode 100644 templates/tooltip/domainCard.hbs create mode 100644 templates/tooltip/weapon.hbs diff --git a/daggerheart.mjs b/daggerheart.mjs index dbe5aa21..2415c857 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -124,6 +124,7 @@ Hooks.once('init', () => { CONFIG.ui.resources = Resources; CONFIG.ux.ContextMenu = applications.DhContextMenu; + CONFIG.ux.TooltipManager = applications.DhTooltipManager; game.socket.on(`system.${SYSTEM.id}`, handleSocketEvent); diff --git a/module/applications/_module.mjs b/module/applications/_module.mjs index a74cb8cf..1a769052 100644 --- a/module/applications/_module.mjs +++ b/module/applications/_module.mjs @@ -15,5 +15,6 @@ export { default as DhpChatMessage } from './chatMessage.mjs'; export { default as DhpEnvironment } from './sheets/actors/environment.mjs'; export { default as DhActiveEffectConfig } from './sheets/activeEffectConfig.mjs'; export { default as DhContextMenu } from './contextMenu.mjs'; +export { default as DhTooltipManager } from './tooltipManager.mjs'; export * as api from './sheets/api/_modules.mjs'; diff --git a/module/applications/tooltipManager.mjs b/module/applications/tooltipManager.mjs new file mode 100644 index 00000000..d7d3117c --- /dev/null +++ b/module/applications/tooltipManager.mjs @@ -0,0 +1,16 @@ +export default class DhTooltipManager extends TooltipManager { + async activate(element, options = {}) { + let html = options.html; + if (element.dataset.tooltip.startsWith('#item#')) { + const item = await foundry.utils.fromUuid(element.dataset.tooltip.slice(6)); + if (item) { + html = await foundry.applications.handlebars.renderTemplate( + `systems/daggerheart/templates/tooltip/${item.type}.hbs`, + item + ); + } + } + + super.activate(element, { ...options, html: html }); + } +} diff --git a/templates/sheets/global/partials/inventory-item.hbs b/templates/sheets/global/partials/inventory-item.hbs index 491829d1..7c91f032 100644 --- a/templates/sheets/global/partials/inventory-item.hbs +++ b/templates/sheets/global/partials/inventory-item.hbs @@ -1,4 +1,4 @@ -
  • +
  • {{item.name}}
    diff --git a/templates/tooltip/armor.hbs b/templates/tooltip/armor.hbs new file mode 100644 index 00000000..c2972700 --- /dev/null +++ b/templates/tooltip/armor.hbs @@ -0,0 +1,5 @@ +
    +
    {{name}}
    + +
    {{{system.description}}}
    +
    \ No newline at end of file diff --git a/templates/tooltip/domainCard.hbs b/templates/tooltip/domainCard.hbs new file mode 100644 index 00000000..c2972700 --- /dev/null +++ b/templates/tooltip/domainCard.hbs @@ -0,0 +1,5 @@ +
    +
    {{name}}
    + +
    {{{system.description}}}
    +
    \ No newline at end of file diff --git a/templates/tooltip/weapon.hbs b/templates/tooltip/weapon.hbs new file mode 100644 index 00000000..c2972700 --- /dev/null +++ b/templates/tooltip/weapon.hbs @@ -0,0 +1,5 @@ +
    +
    {{name}}
    + +
    {{{system.description}}}
    +
    \ No newline at end of file From ac7fb93635d4d67d6d220e94dae836156816e561 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Wed, 2 Jul 2025 23:36:27 +0200 Subject: [PATCH 3/4] [Bug] Potential Adversary When Removed (#248) * Fixed so edit/view/delete of potential adversary is handled if the adversary Actor has been removed from the world * Improved lang --- lang/en.json | 5 +++++ .../sheets/actors/environment.mjs | 19 ++++++++++++++----- .../applications/environment-settings.mjs | 9 ++++++++- .../sheets/global/partials/inventory-item.hbs | 2 +- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/lang/en.json b/lang/en.json index 49196f50..e903ee5c 100755 --- a/lang/en.json +++ b/lang/en.json @@ -20,6 +20,11 @@ } }, "DAGGERHEART": { + "UI": { + "notifications": { + "adversaryMissing": "The linked adversary doesn't exist in the world." + } + }, "Settings": { "Menu": { "Automation": { diff --git a/module/applications/sheets/actors/environment.mjs b/module/applications/sheets/actors/environment.mjs index 1440bb4e..dc0da8e9 100644 --- a/module/applications/sheets/actors/environment.mjs +++ b/module/applications/sheets/actors/environment.mjs @@ -12,7 +12,6 @@ export default class DhpEnvironment extends DaggerheartSheet(ActorSheetV2) { actions: { addAdversary: this.addAdversary, deleteProperty: this.deleteProperty, - viewAdversary: this.viewAdversary, openSettings: this.openSettings, useItem: this.useItem, toChat: this.toChat @@ -103,14 +102,24 @@ export default class DhpEnvironment extends DaggerheartSheet(ActorSheetV2) { this.render(); } - static async viewAdversary(_, button) { - const adversary = await foundry.utils.fromUuid(button.dataset.adversary); + async viewAdversary(_, button) { + const target = button.closest('[data-item-uuid]'); + const adversary = await foundry.utils.fromUuid(target.dataset.itemUuid); + if (!adversary) { + ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.notifications.adversaryMissing')); + return; + } + adversary.sheet.render(true); } - static async useItem(event) { + static async useItem(event, button) { const action = this.getAction(event); - action.use(event); + if (!action) { + await this.viewAdversary(event, button); + } else { + action.use(event); + } } static async toChat(event) { diff --git a/module/applications/sheets/applications/environment-settings.mjs b/module/applications/sheets/applications/environment-settings.mjs index 1f3c33c8..fa58893b 100644 --- a/module/applications/sheets/applications/environment-settings.mjs +++ b/module/applications/sheets/applications/environment-settings.mjs @@ -181,13 +181,20 @@ export default class DHEnvironmentSettings extends HandlebarsApplicationMixin(Ap static async #viewAdversary(_, button) { const adversary = await foundry.utils.fromUuid(button.dataset.adversary); + if (!adversary) { + ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.notifications.adversaryMissing')); + return; + } + adversary.sheet.render(true); } static async #deleteAdversary(event, target) { const adversaryKey = target.dataset.adversary; const path = `system.potentialAdversaries.${target.dataset.potentialAdversary}.adversaries`; - const newAdversaries = foundry.utils.getProperty(this.actor, path).filter(x => x.uuid !== adversaryKey); + const newAdversaries = foundry.utils + .getProperty(this.actor, path) + .filter(x => x && (x?.uuid ?? x) !== adversaryKey); await this.actor.update({ [path]: newAdversaries }); this.render(); } diff --git a/templates/sheets/global/partials/inventory-item.hbs b/templates/sheets/global/partials/inventory-item.hbs index 7c91f032..b69f1a2d 100644 --- a/templates/sheets/global/partials/inventory-item.hbs +++ b/templates/sheets/global/partials/inventory-item.hbs @@ -1,4 +1,4 @@ -
  • +
  • {{item.name}}
    From a79b7189b6dd5c0ee9e41f11113c1c14b8085cb4 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Wed, 2 Jul 2025 23:37:23 +0200 Subject: [PATCH 4/4] 229 - Narrative Countdown Window Update (#237) * Improved * Fixed the mode not sticking * Removed console log --- lang/en.json | 1 + module/applications/countdowns.mjs | 92 ++++++++++++++-------- module/applications/roll.mjs | 5 +- module/config/flagsConfig.mjs | 8 ++ module/data/action/action.mjs | 45 +++++++---- module/data/chat-message/adversaryRoll.mjs | 7 +- module/data/chat-message/damageRoll.mjs | 9 ++- module/data/chat-message/dualityRoll.mjs | 2 +- module/data/countdowns.mjs | 3 +- module/documents/actor.mjs | 4 +- module/helpers/utils.mjs | 22 ++++++ module/ui/chatLog.mjs | 42 ++++++---- styles/chat.less | 26 +++--- styles/countdown.less | 65 ++++++--------- styles/daggerheart.css | 37 +++------ templates/views/countdowns.hbs | 77 +++++++++--------- 16 files changed, 258 insertions(+), 187 deletions(-) diff --git a/lang/en.json b/lang/en.json index e903ee5c..7867265d 100755 --- a/lang/en.json +++ b/lang/en.json @@ -1138,6 +1138,7 @@ "RemoveCountdownText": "Are you sure you want to remove the countdown: {name}?", "OpenOwnership": "Edit Player Ownership", "Title": "{type} Countdowns", + "ToggleSimple": "Toggle Simple View", "Types": { "narrative": "Narrative", "encounter": "Encounter" diff --git a/module/applications/countdowns.mjs b/module/applications/countdowns.mjs index 9fcb0a2b..54c999a9 100644 --- a/module/applications/countdowns.mjs +++ b/module/applications/countdowns.mjs @@ -1,5 +1,6 @@ import { countdownTypes } from '../config/generalConfig.mjs'; import { GMUpdateEvent, RefreshType, socketEvent } from '../helpers/socket.mjs'; +import constructHTMLButton from '../helpers/utils.mjs'; import OwnershipSelection from './ownershipSelection.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -25,14 +26,15 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) { frame: true, title: 'Countdowns', resizable: true, - minimizable: true + minimizable: false }, actions: { addCountdown: this.addCountdown, removeCountdown: this.removeCountdown, editImage: this.onEditImage, openOwnership: this.openOwnership, - openCountdownOwnership: this.openCountdownOwnership + openCountdownOwnership: this.openCountdownOwnership, + toggleSimpleView: this.toggleSimpleView }, form: { handler: this.updateData, submitOnChange: true } }; @@ -53,11 +55,47 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) { }); } - async _onFirstRender(context, options) { - super._onFirstRender(context, options); + async _preFirstRender(context, options) { + options.position = + game.user.getFlag(SYSTEM.id, SYSTEM.FLAGS[`${this.basePath}Countdown`].position) ?? + Countdowns.DEFAULT_OPTIONS.position; - this.element.querySelector('.expanded-view').classList.toggle('hidden'); - this.element.querySelector('.minimized-view').classList.toggle('hidden'); + const viewSetting = + game.user.getFlag(SYSTEM.id, SYSTEM.FLAGS[`${this.basePath}Countdown`].simple) ?? !game.user.isGM; + this.simpleView = + game.user.isGM || !this.testUserPermission(CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER) ? viewSetting : true; + context.simple = this.simpleView; + } + + _onPosition(position) { + game.user.setFlag(SYSTEM.id, SYSTEM.FLAGS[`${this.basePath}Countdown`].position, position); + } + + async _renderFrame(options) { + const frame = await super._renderFrame(options); + + if (this.testUserPermission(CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER)) { + const button = constructHTMLButton({ + label: '', + classes: ['header-control', 'icon', 'fa-solid', 'fa-wrench'], + dataset: { action: 'toggleSimpleView', tooltip: 'DAGGERHEART.Countdown.ToggleSimple' } + }); + this.window.controls.after(button); + } + + return frame; + } + + testUserPermission(level, exact, altSettings) { + if (game.user.isGM) return true; + + const settings = + altSettings ?? game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns)[this.basePath]; + const defaultAllowed = exact ? settings.ownership.default === level : settings.ownership.default >= level; + const userAllowed = exact + ? settings.playerOwnership[game.user.id]?.value === level + : settings.playerOwnership[game.user.id]?.value >= level; + return defaultAllowed || userAllowed; } async _prepareContext(_options) { @@ -67,15 +105,17 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) { context.isGM = game.user.isGM; context.base = this.basePath; - context.canCreate = countdownData.playerOwnership[game.user.id].value === CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER; + context.canCreate = this.testUserPermission(CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER, true); context.source = { ...countdownData, countdowns: Object.keys(countdownData.countdowns).reduce((acc, key) => { const countdown = countdownData.countdowns[key]; - const ownershipValue = countdown.playerOwnership[game.user.id].value; - if (ownershipValue > CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE) { - acc[key] = { ...countdown, canEdit: ownershipValue === CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER }; + if (this.testUserPermission(CONST.DOCUMENT_OWNERSHIP_LEVELS.LIMITED, false, countdown)) { + acc[key] = { + ...countdown, + canEdit: this.testUserPermission(CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER, true, countdown) + }; } return acc; @@ -83,7 +123,7 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) { }; context.systemFields = countdownData.schema.fields; context.countdownFields = context.systemFields.countdowns.element.fields; - context.minimized = this.minimized || _options.isFirstRender; + context.simple = this.simpleView; return context; } @@ -110,28 +150,6 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) { } } - async minimize() { - await super.minimize(); - - this.element.querySelector('.expanded-view').classList.toggle('hidden'); - this.element.querySelector('.minimized-view').classList.toggle('hidden'); - } - - async maximize() { - if (this.minimized) { - const settings = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns)[this.basePath]; - if (settings.playerOwnership[game.user.id].value <= CONST.DOCUMENT_OWNERSHIP_LEVELS.LIMITED) { - ui.notifications.info(game.i18n.localize('DAGGERHEART.Countdown.Notifications.LimitedOwnership')); - return; - } - - this.element.querySelector('.expanded-view').classList.toggle('hidden'); - this.element.querySelector('.minimized-view').classList.toggle('hidden'); - } - - await super.maximize(); - } - async updateSetting(update) { if (game.user.isGM) { await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, update); @@ -213,11 +231,17 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) { }); } + static async toggleSimpleView() { + this.simpleView = !this.simpleView; + await game.user.setFlag(SYSTEM.id, SYSTEM.FLAGS[`${this.basePath}Countdown`].simple, this.simpleView); + this.render(); + } + async updateCountdownValue(event, increase) { const countdownSetting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns); const countdown = countdownSetting[this.basePath].countdowns[event.currentTarget.dataset.countdown]; - if (countdown.playerOwnership[game.user.id] < CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) { + if (!this.testUserPermission(CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)) { return; } diff --git a/module/applications/roll.mjs b/module/applications/roll.mjs index 1c89644f..75d78938 100644 --- a/module/applications/roll.mjs +++ b/module/applications/roll.mjs @@ -56,7 +56,6 @@ export class DHRoll extends Roll { } static async buildPost(roll, config, message) { - console.log(config) for (const hook of config.hooks) { if (Hooks.call(`${SYSTEM.id}.postRoll${hook.capitalize()}`, config, message) === false) return null; } @@ -441,9 +440,9 @@ export class DamageRoll extends DHRoll { static async postEvaluate(roll, config = {}) { super.postEvaluate(roll, config); config.roll.type = config.type; - if(config.source?.message) { + if (config.source?.message) { const chatMessage = ui.chat.collection.get(config.source.message); - chatMessage.update({'system.damage': config}); + chatMessage.update({ 'system.damage': config }); } } } diff --git a/module/config/flagsConfig.mjs b/module/config/flagsConfig.mjs index b06a36e1..252863f1 100644 --- a/module/config/flagsConfig.mjs +++ b/module/config/flagsConfig.mjs @@ -1 +1,9 @@ export const displayDomainCardsAsList = 'displayDomainCardsAsList'; +export const narrativeCountdown = { + simple: 'countdown-narrative-simple', + position: 'countdown-narrative-position' +}; +export const encounterCountdown = { + simple: 'countdown-encounter-simple', + position: 'countdown-encounter-position' +}; diff --git a/module/data/action/action.mjs b/module/data/action/action.mjs index 33b7280a..7bda6089 100644 --- a/module/data/action/action.mjs +++ b/module/data/action/action.mjs @@ -403,11 +403,18 @@ export class DHBaseAction extends foundry.abstract.DataModel { hasCost(costs) { const realCosts = this.getRealCosts(costs), hasFearCost = realCosts.findIndex(c => c.type === 'fear'); - if(hasFearCost > -1) { + if (hasFearCost > -1) { const fearCost = realCosts.splice(hasFearCost, 1); - if(!game.user.isGM || fearCost[0].total > game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear)) return false; + if ( + !game.user.isGM || + fearCost[0].total > game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear) + ) + return false; } - return realCosts.reduce((a, c) => a && this.actor.system.resources[c.type]?.value >= (c.total ?? c.value), true); + return realCosts.reduce( + (a, c) => a && this.actor.system.resources[c.type]?.value >= (c.total ?? c.value), + true + ); } /* COST */ @@ -499,19 +506,25 @@ export class DHBaseAction extends foundry.abstract.DataModel { /* SAVE */ async rollSave(target, event, message) { - if(!target?.actor) return; - return target.actor.diceRoll({ - event, - title: 'Roll Save', - roll: { - trait: this.save.trait, - difficulty: this.save.difficulty, - type: "reaction" - }, - data: target.actor.getRollData() - }).then(async (result) => { - if(result) this.updateChatMessage(message, target.id, {result: result.roll.total, success: result.roll.success}); - }) + if (!target?.actor) return; + return target.actor + .diceRoll({ + event, + title: 'Roll Save', + roll: { + trait: this.save.trait, + difficulty: this.save.difficulty, + type: 'reaction' + }, + data: target.actor.getRollData() + }) + .then(async result => { + if (result) + this.updateChatMessage(message, target.id, { + result: result.roll.total, + success: result.roll.success + }); + }); } async updateChatMessage(message, targetId, changes, chain = true) { diff --git a/module/data/chat-message/adversaryRoll.mjs b/module/data/chat-message/adversaryRoll.mjs index dffeeb20..8a54af48 100644 --- a/module/data/chat-message/adversaryRoll.mjs +++ b/module/data/chat-message/adversaryRoll.mjs @@ -1,4 +1,4 @@ -import { DHBaseAction } from "../action/action.mjs"; +import { DHBaseAction } from '../action/action.mjs'; const fields = foundry.data.fields; @@ -42,6 +42,9 @@ export default class DHAdversaryRoll extends foundry.abstract.TypeDataModel { prepareDerivedData() { this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0; - this.currentTargets = this.targetSelection !== true ? Array.from(game.user.targets).map(t => DHBaseAction.formatTarget(t)) : this.targets; + this.currentTargets = + this.targetSelection !== true + ? Array.from(game.user.targets).map(t => DHBaseAction.formatTarget(t)) + : this.targets; } } diff --git a/module/data/chat-message/damageRoll.mjs b/module/data/chat-message/damageRoll.mjs index 9c83a58a..5e692d97 100644 --- a/module/data/chat-message/damageRoll.mjs +++ b/module/data/chat-message/damageRoll.mjs @@ -3,7 +3,7 @@ export default class DHDamageRoll extends foundry.abstract.TypeDataModel { const fields = foundry.data.fields; return { - messageType: new fields.StringField({initial: 'damage'}), + messageType: new fields.StringField({ initial: 'damage' }), title: new fields.StringField(), roll: new fields.DataField({}), targets: new fields.ArrayField( @@ -28,7 +28,7 @@ export default class DHDamageRoll extends foundry.abstract.TypeDataModel { action: new fields.StringField(), message: new fields.StringField() }), - directDamage: new fields.BooleanField({initial: true}) + directDamage: new fields.BooleanField({ initial: true }) }; } @@ -38,6 +38,9 @@ export default class DHDamageRoll extends foundry.abstract.TypeDataModel { prepareDerivedData() { this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0; - this.currentTargets = this.targetSelection !== true ? Array.from(game.user.targets).map(t => DHBaseAction.formatTarget(t)) : this.targets; + this.currentTargets = + this.targetSelection !== true + ? Array.from(game.user.targets).map(t => DHBaseAction.formatTarget(t)) + : this.targets; } } diff --git a/module/data/chat-message/dualityRoll.mjs b/module/data/chat-message/dualityRoll.mjs index 8b817ab1..a6ffd85b 100644 --- a/module/data/chat-message/dualityRoll.mjs +++ b/module/data/chat-message/dualityRoll.mjs @@ -1,4 +1,4 @@ -import DHAdversaryRoll from "./adversaryRoll.mjs"; +import DHAdversaryRoll from './adversaryRoll.mjs'; export default class DHDualityRoll extends DHAdversaryRoll { get messageTemplate() { diff --git a/module/data/countdowns.mjs b/module/data/countdowns.mjs index e71cda55..a61a1aab 100644 --- a/module/data/countdowns.mjs +++ b/module/data/countdowns.mjs @@ -36,7 +36,8 @@ class DhCountdownData extends foundry.abstract.DataModel { }) }) ) - }) + }), + window: new fields.SchemaField({}) }; } diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 15001bec..541b76d0 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -485,7 +485,9 @@ export default class DhpActor extends Actor { resources.forEach(r => { switch (r.type) { case 'fear': - ui.resources.updateFear(game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear) + r.value); + ui.resources.updateFear( + game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear) + r.value + ); break; case 'armorStack': updates.armor.resources['system.marks.value'] = Math.max( diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index 7816d0f4..990d0b35 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -259,6 +259,28 @@ export const damageKeyToNumber = key => { } }; +export default function constructHTMLButton({ + label, + dataset = {}, + classes = [], + icon = '', + type = 'button', + disabled = false +}) { + const button = document.createElement('button'); + button.type = type; + + for (const [key, value] of Object.entries(dataset)) { + button.dataset[key] = value; + } + button.classList.add(...classes); + if (icon) icon = ` `; + if (disabled) button.disabled = true; + button.innerHTML = `${icon}${label}`; + + return button; +} + export const adjustDice = (dice, decrease) => { const diceKeys = Object.keys(diceTypes); const index = diceKeys.indexOf(dice); diff --git a/module/ui/chatLog.mjs b/module/ui/chatLog.mjs index 719a5428..14d99734 100644 --- a/module/ui/chatLog.mjs +++ b/module/ui/chatLog.mjs @@ -37,7 +37,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo element.addEventListener('click', this.clickTarget); }); html.querySelectorAll('.button-target-selection').forEach(element => { - element.addEventListener('click', event => this.onTargetSelection(event, data.message)) + element.addEventListener('click', event => this.onTargetSelection(event, data.message)); }); html.querySelectorAll('.damage-button').forEach(element => element.addEventListener('click', event => this.onDamage(event, data.message)) @@ -122,11 +122,13 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo onRollAllSave = async (event, message) => { event.stopPropagation(); - const targets = event.target.parentElement.querySelectorAll('.target-section > [data-token] .target-save-container'); - targets.forEach((el) => { - el.dispatchEvent(new PointerEvent("click", { shiftKey: true})) - }) - } + const targets = event.target.parentElement.querySelectorAll( + '.target-section > [data-token] .target-save-container' + ); + targets.forEach(el => { + el.dispatchEvent(new PointerEvent('click', { shiftKey: true })); + }); + }; onApplyEffect = async (event, message) => { event.stopPropagation(); @@ -146,18 +148,26 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo event.stopPropagation(); const targetSelection = Boolean(event.target.dataset.targetHit), msg = ui.chat.collection.get(message._id); - if(msg.system.targetSelection === targetSelection) return; - if(targetSelection !== true && !Array.from(game.user.targets).length) return ui.notifications.info(game.i18n.localize('DAGGERHEART.Notification.Info.NoTargetsSelected')); + if (msg.system.targetSelection === targetSelection) return; + if (targetSelection !== true && !Array.from(game.user.targets).length) + return ui.notifications.info(game.i18n.localize('DAGGERHEART.Notification.Info.NoTargetsSelected')); msg.system.targetSelection = targetSelection; msg.system.prepareDerivedData(); ui.chat.updateMessage(msg); - } + }; getTargetList = (event, message) => { - const targetSelection = event.target.closest('.message-content').querySelector('.button-target-selection.target-selected'), + const targetSelection = event.target + .closest('.message-content') + .querySelector('.button-target-selection.target-selected'), isHit = Boolean(targetSelection.dataset.targetHit); - return {isHit, targets: isHit ? message.system.targets.filter(t => t.hit === true).map(target => game.canvas.tokens.get(target.id)) : Array.from(game.user.targets)}; - } + return { + isHit, + targets: isHit + ? message.system.targets.filter(t => t.hit === true).map(target => game.canvas.tokens.get(target.id)) + : Array.from(game.user.targets) + }; + }; hoverTarget = event => { event.stopPropagation(); @@ -185,9 +195,11 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo event.stopPropagation(); const { isHit, targets } = this.getTargetList(event, message); - if(message.system.onSave && isHit) { - const pendingingSaves = message.system.targets.filter(target => target.hit && target.saved.success === null); - if(pendingingSaves.length) { + if (message.system.onSave && isHit) { + const pendingingSaves = message.system.targets.filter( + target => target.hit && target.saved.success === null + ); + if (pendingingSaves.length) { const confirm = await foundry.applications.api.DialogV2.confirm({ window: { title: 'Pending Reaction Rolls found' }, content: `

    Some Tokens still need to roll their Reaction Roll.

    Are you sure you want to continue ?

    Undone reaction rolls will be considered as failed

    ` diff --git a/styles/chat.less b/styles/chat.less index c0e45af4..f454bec7 100644 --- a/styles/chat.less +++ b/styles/chat.less @@ -15,13 +15,15 @@ fieldset.daggerheart.chat { display: flex; align-items: center; gap: 5px; - &:before, &:after { + &:before, + &:after { content: '\f0d8'; - font-family: "Font Awesome 6 Pro"; + font-family: 'Font Awesome 6 Pro'; } } &.expanded { - legend:before, legend:after { + legend:before, + legend:after { content: '\f0d7'; } } @@ -229,20 +231,20 @@ fieldset.daggerheart.chat { .target-selection { display: flex; justify-content: space-around; - input[type="radio"] { + input[type='radio'] { display: none; &:checked + label { - text-shadow: 0px 0px 4px #CE5937; + text-shadow: 0px 0px 4px #ce5937; } &:not(:checked) + label { - opacity: .75; + opacity: 0.75; } } label { cursor: pointer; - opacity: .75; + opacity: 0.75; &.target-selected { - text-shadow: 0px 0px 4px #CE5937; + text-shadow: 0px 0px 4px #ce5937; opacity: 1; } } @@ -273,7 +275,8 @@ fieldset.daggerheart.chat { background: @miss; } - img, .target-save-container { + img, + .target-save-container { width: 22px; height: 22px; align-self: center; @@ -401,7 +404,7 @@ fieldset.daggerheart.chat { display: none; } &::after { - content: "??"; + content: '??'; } } } @@ -414,7 +417,8 @@ fieldset.daggerheart.chat { border-top-width: 0; display: contents; legend { - &:before, &:after { + &:before, + &:after { display: none; } } diff --git a/styles/countdown.less b/styles/countdown.less index dd80acc4..336805a9 100644 --- a/styles/countdown.less +++ b/styles/countdown.less @@ -1,6 +1,6 @@ .theme-light { .daggerheart.dh-style.countdown { - &.minimized .minimized-view .mini-countdown-container { + .minimized-view .mini-countdown-container { background-image: url('../assets/parchments/dh-parchment-dark.png'); } } @@ -26,51 +26,38 @@ } } - &.minimized { - height: auto !important; - max-height: unset !important; - max-width: 740px !important; - width: auto !important; + .minimized-view { + display: flex; + gap: 8px; + flex-wrap: wrap; - .window-content { - display: flex; - padding: 4px 8px; - justify-content: center; - } - - .minimized-view { + .mini-countdown-container { + width: fit-content; display: flex; + align-items: center; gap: 8px; - flex-wrap: wrap; + border: 2px solid light-dark(@dark-blue, @golden); + border-radius: 6px; + padding: 0 4px 0 0; + background-image: url('../assets/parchments/dh-parchment-light.png'); + color: light-dark(@beige, @dark); + cursor: pointer; - .mini-countdown-container { - width: fit-content; - display: flex; - align-items: center; - gap: 8px; - border: 2px solid light-dark(@dark-blue, @golden); - border-radius: 6px; - padding: 0 4px 0 0; - background-image: url('../assets/parchments/dh-parchment-light.png'); - color: light-dark(@beige, @dark); - cursor: pointer; + &.disabled { + cursor: initial; + } - &.disabled { - cursor: initial; - } + img { + width: 30px; + height: 30px; + border-radius: 6px 0 0 6px; + } - img { - width: 30px; - height: 30px; - border-radius: 6px 0 0 6px; - } + .mini-countdown-name { + white-space: nowrap; + } - .mini-countdown-name { - white-space: nowrap; - } - - .mini-countdown-value { - } + .mini-countdown-value { } } } diff --git a/styles/daggerheart.css b/styles/daggerheart.css index dc9cdabb..4d8546b1 100755 --- a/styles/daggerheart.css +++ b/styles/daggerheart.css @@ -1414,7 +1414,7 @@ fieldset.daggerheart.chat legend { fieldset.daggerheart.chat legend:before, fieldset.daggerheart.chat legend:after { content: '\f0d8'; - font-family: "Font Awesome 6 Pro"; + font-family: 'Font Awesome 6 Pro'; } fieldset.daggerheart.chat.expanded legend:before, fieldset.daggerheart.chat.expanded legend:after { @@ -1559,13 +1559,13 @@ fieldset.daggerheart.chat .daggerheart.chat { display: flex; justify-content: space-around; } -.daggerheart.chat.roll .target-selection input[type="radio"] { +.daggerheart.chat.roll .target-selection input[type='radio'] { display: none; } -.daggerheart.chat.roll .target-selection input[type="radio"]:checked + label { - text-shadow: 0px 0px 4px #CE5937; +.daggerheart.chat.roll .target-selection input[type='radio']:checked + label { + text-shadow: 0px 0px 4px #ce5937; } -.daggerheart.chat.roll .target-selection input[type="radio"]:not(:checked) + label { +.daggerheart.chat.roll .target-selection input[type='radio']:not(:checked) + label { opacity: 0.75; } .daggerheart.chat.roll .target-selection label { @@ -1573,7 +1573,7 @@ fieldset.daggerheart.chat .daggerheart.chat { opacity: 0.75; } .daggerheart.chat.roll .target-selection label.target-selected { - text-shadow: 0px 0px 4px #CE5937; + text-shadow: 0px 0px 4px #ce5937; opacity: 1; } .daggerheart.chat.roll .target-section { @@ -1700,7 +1700,7 @@ fieldset.daggerheart.chat .daggerheart.chat { display: none; } .daggerheart.chat [data-view-perm='false']::after { - content: "??"; + content: '??'; } .theme-colorful .chat-message.duality { border-color: black; @@ -3474,7 +3474,7 @@ div.daggerheart.views.multiclass { #resources:has(.fear-bar) { min-width: 200px; } -.theme-light .daggerheart.dh-style.countdown.minimized .minimized-view .mini-countdown-container { +.theme-light .daggerheart.dh-style.countdown .minimized-view .mini-countdown-container { background-image: url('../assets/parchments/dh-parchment-dark.png'); } .daggerheart.dh-style.countdown { @@ -3494,23 +3494,12 @@ div.daggerheart.views.multiclass { .daggerheart.dh-style.countdown fieldset legend a { text-shadow: none; } -.daggerheart.dh-style.countdown.minimized { - height: auto !important; - max-height: unset !important; - max-width: 740px !important; - width: auto !important; -} -.daggerheart.dh-style.countdown.minimized .window-content { - display: flex; - padding: 4px 8px; - justify-content: center; -} -.daggerheart.dh-style.countdown.minimized .minimized-view { +.daggerheart.dh-style.countdown .minimized-view { display: flex; gap: 8px; flex-wrap: wrap; } -.daggerheart.dh-style.countdown.minimized .minimized-view .mini-countdown-container { +.daggerheart.dh-style.countdown .minimized-view .mini-countdown-container { width: fit-content; display: flex; align-items: center; @@ -3522,15 +3511,15 @@ div.daggerheart.views.multiclass { color: light-dark(#efe6d8, #222); cursor: pointer; } -.daggerheart.dh-style.countdown.minimized .minimized-view .mini-countdown-container.disabled { +.daggerheart.dh-style.countdown .minimized-view .mini-countdown-container.disabled { cursor: initial; } -.daggerheart.dh-style.countdown.minimized .minimized-view .mini-countdown-container img { +.daggerheart.dh-style.countdown .minimized-view .mini-countdown-container img { width: 30px; height: 30px; border-radius: 6px 0 0 6px; } -.daggerheart.dh-style.countdown.minimized .minimized-view .mini-countdown-container .mini-countdown-name { +.daggerheart.dh-style.countdown .minimized-view .mini-countdown-container .mini-countdown-name { white-space: nowrap; } .daggerheart.dh-style.countdown .hidden { diff --git a/templates/views/countdowns.hbs b/templates/views/countdowns.hbs index 293b84b9..f06aa4db 100644 --- a/templates/views/countdowns.hbs +++ b/templates/views/countdowns.hbs @@ -1,42 +1,45 @@
    -
    -
    - {{#if canCreate}}{{/if}} - {{#if isGM}}{{/if}} -
    - -
    + {{#if simple}} +
    {{#each source.countdowns}} -
    - - {{this.name}} - {{#if this.canEdit}}{{/if}} - {{#if @root.isGM}}{{/if}} - - - -
    - -
    - {{formGroup @root.countdownFields.name name=(concat @root.base ".countdowns." @key ".name") value=this.name localize=true disabled=(not this.canEdit)}} -
    - {{formGroup @root.countdownFields.progress.fields.current name=(concat @root.base ".countdowns." @key ".progress.current") value=this.progress.current localize=true disabled=(not this.canEdit)}} - {{formGroup @root.countdownFields.progress.fields.max name=(concat @root.base ".countdowns." @key ".progress.max") value=this.progress.max localize=true disabled=(not this.canEdit)}} -
    - {{formGroup @root.countdownFields.progress.fields.type.fields.value name=(concat @root.base ".countdowns." @key ".progress.type.value") value=this.progress.type.value localize=true localize=true disabled=(not this.canEdit)}} -
    -
    -
    + + +
    {{this.name}}
    +
    {{this.progress.current}}/{{this.progress.max}}
    +
    {{/each}}
    -
    - + {{else}} +
    +
    + {{#if canCreate}}{{/if}} + {{#if isGM}}{{/if}} +
    + +
    + {{#each source.countdowns}} +
    + + {{this.name}} + {{#if this.canEdit}}{{/if}} + {{#if @root.isGM}}{{/if}} + + + +
    + +
    + {{formGroup @root.countdownFields.name name=(concat @root.base ".countdowns." @key ".name") value=this.name localize=true disabled=(not this.canEdit)}} +
    + {{formGroup @root.countdownFields.progress.fields.current name=(concat @root.base ".countdowns." @key ".progress.current") value=this.progress.current localize=true disabled=(not this.canEdit)}} + {{formGroup @root.countdownFields.progress.fields.max name=(concat @root.base ".countdowns." @key ".progress.max") value=this.progress.max localize=true disabled=(not this.canEdit)}} +
    + {{formGroup @root.countdownFields.progress.fields.type.fields.value name=(concat @root.base ".countdowns." @key ".progress.type.value") value=this.progress.type.value localize=true localize=true disabled=(not this.canEdit)}} +
    +
    +
    + {{/each}} +
    +
    + {{/if}}
    \ No newline at end of file