diff --git a/daggerheart.mjs b/daggerheart.mjs index 071a8bce..e9af1a1f 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -125,6 +125,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/lang/en.json b/lang/en.json index 30673555..093b63e9 100755 --- a/lang/en.json +++ b/lang/en.json @@ -21,6 +21,11 @@ } }, "DAGGERHEART": { + "UI": { + "notifications": { + "adversaryMissing": "The linked adversary doesn't exist in the world." + } + }, "Settings": { "Menu": { "Automation": { @@ -193,6 +198,10 @@ "Full": "Disadvantage", "Short": "Dis" }, + "Neutral": { + "Full": "None", + "Short": "no" + }, "OK": "OK", "Cancel": "Cancel", "Or": "Or", @@ -1130,6 +1139,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/_module.mjs b/module/applications/_module.mjs index a2b82a75..e16a66fe 100644 --- a/module/applications/_module.mjs +++ b/module/applications/_module.mjs @@ -16,5 +16,6 @@ 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 DhBeastform } from './sheets/items/beastform.mjs'; +export { default as DhTooltipManager } from './tooltipManager.mjs'; export * as api from './sheets/api/_modules.mjs'; 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/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..509402f2 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; } @@ -54,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; } @@ -98,9 +99,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)); } } @@ -114,10 +133,6 @@ 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 +155,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 +168,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 +186,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 +244,14 @@ 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 = [ - { - label: 'Bonus to Hit', - value: Roll.replaceFormulaData('@attackBonus', this.data) - } - ]; + this.options.roll.modifiers = []; + if (!this.options.roll.bonus) return; + this.options.roll.modifiers.push({ + label: 'Bonus to Hit', + value: this.options.roll.bonus + // value: Roll.replaceFormulaData('@attackBonus', this.data) + }); } static postEvaluate(roll, config = {}) { @@ -245,23 +264,27 @@ export class D20Roll extends DHRoll { } 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 +293,8 @@ export class D20Roll extends DHRoll { } export class DualityRoll extends D20Roll { + _advantageFaces = 6; + constructor(formula, data = {}, options = {}) { super(formula, data, options); } @@ -287,7 +312,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 +325,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 +333,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,21 +370,23 @@ 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 - ) + ) { + 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) @@ -372,12 +407,12 @@ export class DualityRoll extends D20Roll { } applyBaseBonus() { - this.options.roll.modifiers = [ - { - label: `DAGGERHEART.Abilities.${this.options.roll.trait}.name`, - value: Roll.replaceFormulaData(`@traits.${this.options.roll.trait}.total`, this.data) - } - ]; + 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 = {}) { @@ -410,9 +445,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/applications/rollSelectionDialog.mjs b/module/applications/rollSelectionDialog.mjs index 0a1972aa..543fa6c5 100644 --- a/module/applications/rollSelectionDialog.mjs +++ b/module/applications/rollSelectionDialog.mjs @@ -1,9 +1,11 @@ +/** NOT USED ANYMORE - TO BE DELETED **/ + const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; export default class RollSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) { constructor(experiences, costs, action, resolve) { super({}, {}); - + this.experiences = experiences; this.costs = costs; this.action = action; @@ -65,9 +67,9 @@ export default class RollSelectionDialog extends HandlebarsApplicationMixin(Appl context.fear = this.data.fear; context.advantage = this.data.advantage; context.experiences = Object.keys(this.experiences).map(id => ({ id, ...this.experiences[id] })); - if(this.costs?.length) { + if (this.costs?.length) { const updatedCosts = this.action.calcCosts(this.costs); - context.costs = updatedCosts + context.costs = updatedCosts; context.canRoll = this.action.getRealCosts(updatedCosts)?.hasCost; } else context.canRoll = true; 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/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/adversary-settings.mjs b/module/applications/sheets/applications/adversary-settings.mjs index 2ecdcb60..70fae0cb 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/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/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/module/config/actionConfig.mjs b/module/config/actionConfig.mjs index 1ac34889..4dc65fd7 100644 --- a/module/config/actionConfig.mjs +++ b/module/config/actionConfig.mjs @@ -110,3 +110,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/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 eac05a7f..ff38ae3f 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'; @@ -349,7 +348,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; @@ -378,7 +379,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/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/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..08792c40 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..afec593b 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/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 77aa892b..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; } } @@ -493,16 +497,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/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 73b4750c..c1fd3028 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; @@ -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 { @@ -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 { @@ -5423,6 +5412,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 @@