diff --git a/daggerheart.mjs b/daggerheart.mjs index c881801f..a6676f19 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -17,6 +17,7 @@ import { socketRegistration } from './module/systemRegistration/_module.mjs'; import { placeables } from './module/canvas/_module.mjs'; +import { registerRollDiceHooks } from './module/dice/dhRoll.mjs'; Hooks.once('init', () => { CONFIG.DH = SYSTEM; @@ -152,6 +153,7 @@ Hooks.on('ready', () => { registerCountdownHooks(); socketRegistration.registerSocketHooks(); registerCountdownApplicationHooks(); + registerRollDiceHooks(); }); Hooks.once('dicesoniceready', () => {}); @@ -209,7 +211,7 @@ Hooks.on('chatMessage', (_, message) => { } const title = traitValue - ? game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilitychecktitle', { + ? game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { ability: game.i18n.localize(SYSTEM.ACTOR.abilities[traitValue].label) }) : game.i18n.localize('DAGGERHEART.GENERAL.duality'); diff --git a/module/applications/dialogs/d20RollDialog.mjs b/module/applications/dialogs/d20RollDialog.mjs index 7eaeacb3..db15a7a3 100644 --- a/module/applications/dialogs/d20RollDialog.mjs +++ b/module/applications/dialogs/d20RollDialog.mjs @@ -63,18 +63,6 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio const context = await super._prepareContext(_options); context.rollConfig = this.config; 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.roll?.advantage; - context.disadvantage = this.config.roll?.disadvantage; - context.diceOptions = CONFIG.DH.GENERAL.diceTypes; - context.canRoll = true; - context.isLite = this.config.roll?.lite; if (this.config.costs?.length) { const updatedCosts = this.action.calcCosts(this.config.costs); context.costs = updatedCosts; @@ -85,8 +73,22 @@ 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); + if(this.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.roll?.advantage; + context.disadvantage = this.config.roll?.disadvantage; + context.diceOptions = CONFIG.DH.GENERAL.diceTypes; + context.canRoll = true; + context.isLite = this.config.roll?.lite; + context.extraFormula = this.config.extraFormula; + context.formula = this.roll.constructFormula(this.config); + } return context; } diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index 95bbbec1..5a5120a6 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -494,7 +494,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { const config = { event: event, title: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${this.actor.name}`, - headerTitle: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilitychecktitle', { + headerTitle: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { ability: abilityLabel }), roll: { @@ -605,7 +605,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) { const abilityLabel = game.i18n.localize(abilities[button.dataset.attribute].label); const config = { event: event, - title: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilitychecktitle', { ability: abilityLabel }), + title: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { ability: abilityLabel }), roll: { trait: button.dataset.attribute } diff --git a/module/applications/ui/chatLog.mjs b/module/applications/ui/chatLog.mjs index 8a0ff3e0..d8edf388 100644 --- a/module/applications/ui/chatLog.mjs +++ b/module/applications/ui/chatLog.mjs @@ -158,7 +158,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo const targetSelection = event.target .closest('.message-content') .querySelector('.button-target-selection.target-selected'), - isHit = Boolean(targetSelection.dataset.targetHit); + isHit = Boolean(targetSelection?.dataset?.targetHit) ?? false; return { isHit, targets: isHit diff --git a/module/applications/ui/combatTracker.mjs b/module/applications/ui/combatTracker.mjs index e5414d47..f9f49ad1 100644 --- a/module/applications/ui/combatTracker.mjs +++ b/module/applications/ui/combatTracker.mjs @@ -65,6 +65,20 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C ]; } + async setCombatantSpotlight(combatantId) { + const combatant = this.viewed.combatants.get(combatantId); + + const toggleTurn = this.viewed.combatants.contents + .sort(this.viewed._sortCombatants) + .map(x => x.id) + .indexOf(combatantId); + + if (this.viewed.turn !== toggleTurn) Hooks.callAll(CONFIG.DH.HOOKS.spotlight, {}); + + await this.viewed.update({ turn: this.viewed.turn === toggleTurn ? null : toggleTurn }); + await combatant.update({ 'system.spotlight.requesting': false }); + } + static async requestSpotlight(_, target) { const { combatantId } = target.closest('[data-combatant-id]')?.dataset ?? {}; const combatant = this.viewed.combatants.get(combatantId); @@ -79,17 +93,7 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C static async toggleSpotlight(_, target) { const { combatantId } = target.closest('[data-combatant-id]')?.dataset ?? {}; - const combatant = this.viewed.combatants.get(combatantId); - - const toggleTurn = this.viewed.combatants.contents - .sort(this.viewed._sortCombatants) - .map(x => x.id) - .indexOf(combatantId); - - if (this.viewed.turn !== toggleTurn) Hooks.callAll(CONFIG.DH.HOOKS.spotlight, {}); - - await this.viewed.update({ turn: this.viewed.turn === toggleTurn ? null : toggleTurn }); - await combatant.update({ 'system.spotlight.requesting': false }); + await this.setCombatantSpotlight(combatantId); } static async setActionTokens(_, target) { diff --git a/module/applications/ui/countdowns.mjs b/module/applications/ui/countdowns.mjs index 895ab908..c229cda1 100644 --- a/module/applications/ui/countdowns.mjs +++ b/module/applications/ui/countdowns.mjs @@ -13,7 +13,7 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) { } get title() { - return game.i18n.format('DAGGERHEART.APPLICATIONS.Countdown.Title', { + return game.i18n.format('DAGGERHEART.APPLICATIONS.Countdown.title', { type: game.i18n.localize(`DAGGERHEART.APPLICATIONS.Countdown.types.${this.basePath}`) }); } diff --git a/module/applications/ui/fearTracker.mjs b/module/applications/ui/fearTracker.mjs index c2f56c4c..ace2bbb2 100644 --- a/module/applications/ui/fearTracker.mjs +++ b/module/applications/ui/fearTracker.mjs @@ -1,3 +1,5 @@ +import { emitAsGM, GMUpdateEvent, socketEvent } from "../../systemRegistration/socket.mjs"; + const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; /** @@ -96,6 +98,7 @@ export default class FearTracker extends HandlebarsApplicationMixin(ApplicationV } static async increaseFear(event, target) { + if (!game.user.isGM) return; let value = target.dataset.increment ?? 0, operator = value.split('')[0] ?? null; value = Number(value); @@ -103,8 +106,19 @@ export default class FearTracker extends HandlebarsApplicationMixin(ApplicationV } async updateFear(value) { - if (!game.user.isGM) return; + return emitAsGM(GMUpdateEvent.UpdateFear, game.settings.set.bind(game.settings, CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear), value); + /* if(!game.user.isGM) + await game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.GMUpdate, + data: { + action: GMUpdateEvent.UpdateFear, + update: value + } + }); + else + game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear, value); */ + /* if (!game.user.isGM) return; value = Math.max(0, Math.min(this.maxFear, value)); - await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear, value); + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear, value); */ } } diff --git a/module/data/action/baseAction.mjs b/module/data/action/baseAction.mjs index f797323c..55f08d9a 100644 --- a/module/data/action/baseAction.mjs +++ b/module/data/action/baseAction.mjs @@ -10,14 +10,10 @@ const fields = foundry.data.fields; /* ToDo - - Add setting and/or checkbox for cost and damage like - Target Check / Target Picker - Range Check - Area of effect and measurement placement - Summon Action create method - - Other - - Auto use action <= Into Roll */ export default class DHBaseAction extends foundry.abstract.DataModel { @@ -200,28 +196,23 @@ export default class DHBaseAction extends foundry.abstract.DataModel { const isFastForward = event.shiftKey || (!this.hasRoll && !this.hasSave); // Prepare base Config const initConfig = this.initActionConfig(event); - // let config = this.initActionConfig(event); // Prepare Targets const targetConfig = this.prepareTarget(); if (isFastForward && !targetConfig) return ui.notifications.warn('Too many targets selected for that actions.'); - // config = this.prepareTarget(config); // Prepare Range const rangeConfig = this.prepareRange(); - // config = this.prepareRange(config); // Prepare Costs const costsConfig = this.prepareCost(); if (isFastForward && !this.hasCost(costsConfig)) return ui.notifications.warn("You don't have the resources to use that action."); - // config = this.prepareUseCost(config) // Prepare Uses const usesConfig = this.prepareUse(); if (isFastForward && !this.hasUses(usesConfig)) return ui.notifications.warn("That action doesn't have remaining uses."); - // config = this.prepareUseCost(config) // Prepare Roll Data const actorData = this.getRollData(); @@ -238,8 +229,9 @@ export default class DHBaseAction extends foundry.abstract.DataModel { if (Hooks.call(`${CONFIG.DH.id}.preUseAction`, this, config) === false) return; // Display configuration window if necessary - if (config.dialog?.configure && this.requireConfigurationDialog(config)) { - config = await D20RollDialog.configure(config); + // if (config.dialog?.configure && this.requireConfigurationDialog(config)) { + if (this.requireConfigurationDialog(config)) { + config = await D20RollDialog.configure(null, config); if (!config) return; } @@ -250,37 +242,6 @@ export default class DHBaseAction extends foundry.abstract.DataModel { if (!config) return; } - if (this.hasSave) { - /* config.targets.forEach((t) => { - if(t.hit) { - const target = game.canvas.tokens.get(t.id), - actor = target?.actor; - if(!actor) return; - actor.saveRoll({ - event, - title: 'Roll Save', - roll: { - trait: this.save.trait, - difficulty: this.save.difficulty - }, - dialog: { - configure: false - }, - data: actor.getRollData() - }).then(async (result) => { - t.saved = result; - setTimeout(async () => { - const message = ui.chat.collection.get(config.message.id), - msgTargets = message.system.targets, - msgTarget = msgTargets.find(mt => mt.id === t.id); - msgTarget.saved = result; - await message.update({'system.targets': msgTargets}); - },100) - }) - } - }) */ - } - if (this.doFollowUp()) { if (this.rollDamage) await this.rollDamage(event, config); if (this.rollHealing) await this.rollHealing(event, config); @@ -329,12 +290,12 @@ export default class DHBaseAction extends foundry.abstract.DataModel { } prepareTarget() { + if(!this.target?.type) return []; let targets; if (this.target?.type === CONFIG.DH.ACTIONS.targetTypes.self.id) targets = this.constructor.formatTarget(this.actor.token ?? this.actor.prototypeToken); targets = Array.from(game.user.targets); - // foundry.CONST.TOKEN_DISPOSITIONS.FRIENDLY - if (this.target?.type && this.target.type !== CONFIG.DH.ACTIONS.targetTypes.any.id) { + if (this.target.type !== CONFIG.DH.ACTIONS.targetTypes.any.id) { targets = targets.filter(t => this.isTargetFriendly(t)); if (this.target.amount && targets.length > this.target.amount) targets = []; } @@ -540,6 +501,7 @@ export default class DHBaseAction extends foundry.abstract.DataModel { }); }); } + /* SAVE */ async updateChatMessage(message, targetId, changes, chain = true) { setTimeout(async () => { @@ -558,7 +520,6 @@ export default class DHBaseAction extends foundry.abstract.DataModel { }); } } - /* SAVE */ async toChat(origin) { const cls = getDocumentClass('ChatMessage'); diff --git a/module/data/action/effectAction.mjs b/module/data/action/effectAction.mjs index cfe15305..65425a6f 100644 --- a/module/data/action/effectAction.mjs +++ b/module/data/action/effectAction.mjs @@ -3,38 +3,16 @@ import DHBaseAction from './baseAction.mjs'; export default class DHEffectAction extends DHBaseAction { static extraSchemas = ['effects', 'target']; - async use(event, ...args) { - const config = await super.use(event, args); - if (['error', 'warning'].includes(config.type)) return; - return await this.chatApplyEffects(event, config); - } + async trigger(event, data) { + if(this.effects.length) { + const cls = getDocumentClass('ChatMessage'), + msg = { + type: 'applyEffect', + user: game.user.id, + system: data + }; - async chatApplyEffects(event, data) { - const cls = getDocumentClass('ChatMessage'), - systemData = { - title: game.i18n.format('DAGGERHEART.UI.Chat.applyEffect.title', { name: this.name }), - origin: this.actor._id, - description: '', - targets: data.targets.map(x => ({ id: x.id, name: x.name, img: x.img, hit: true })), - action: { - itemId: this.item._id, - actionId: this._id - } - }, - msg = new cls({ - type: 'applyEffect', - user: game.user.id, - system: systemData, - content: await foundry.applications.handlebars.renderTemplate( - 'systems/daggerheart/templates/ui/chat/apply-effects.hbs', - systemData - ) - }); - - cls.create(msg.toObject()); - } - - get chatTemplate() { - return 'systems/daggerheart/templates/ui/chat/apply-effects.hbs'; + return await cls.create(msg); + } else this.toChat(this.id); } } diff --git a/module/data/chat-message/applyEffects.mjs b/module/data/chat-message/applyEffects.mjs index 838dabfb..a7fdda69 100644 --- a/module/data/chat-message/applyEffects.mjs +++ b/module/data/chat-message/applyEffects.mjs @@ -1,11 +1,11 @@ +import DHBaseAction from "../action/baseAction.mjs"; + export default class DHApplyEffect extends foundry.abstract.TypeDataModel { static defineSchema() { const fields = foundry.data.fields; return { title: new fields.StringField(), - origin: new fields.StringField({}), - description: new fields.StringField({}), targets: new fields.ArrayField( new fields.SchemaField({ id: new fields.StringField({ required: true }), @@ -14,10 +14,24 @@ export default class DHApplyEffect extends foundry.abstract.TypeDataModel { hit: new fields.BooleanField({ initial: false }) }) ), - action: new fields.SchemaField({ - itemId: new fields.StringField(), - actionId: new fields.StringField() + targetSelection: new fields.BooleanField({ initial: true }), + source: new fields.SchemaField({ + actor: new fields.StringField(), + item: new fields.StringField(), + action: new fields.StringField() }) }; } + + 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; + } + + get messageTemplate() { + return 'systems/daggerheart/templates/ui/chat/apply-effects.hbs'; + } } diff --git a/module/data/fields/actionField.mjs b/module/data/fields/actionField.mjs index da520fd1..b83acc2e 100644 --- a/module/data/fields/actionField.mjs +++ b/module/data/fields/actionField.mjs @@ -1,9 +1,6 @@ -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.actions.actionsTypes[value.type] ?? game.system.api.models.actions.actionsTypes.attack; } /* -------------------------------------------- */ diff --git a/module/data/settings/Automation.mjs b/module/data/settings/Automation.mjs index 013e9e1e..4e375919 100644 --- a/module/data/settings/Automation.mjs +++ b/module/data/settings/Automation.mjs @@ -4,9 +4,21 @@ export default class DhAutomation extends foundry.abstract.DataModel { static defineSchema() { const fields = foundry.data.fields; return { - hope: new fields.BooleanField({ required: true, initial: false }), - actionPoints: new fields.BooleanField({ required: true, initial: false }), - countdowns: new fields.BooleanField({ requireD: true, initial: false }) + hope: new fields.BooleanField({ + required: true, + initial: false, + label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.hope.label' + }), // Label need to be updated into something like "Duality Roll Auto Gain" + a hint + actionPoints: new fields.BooleanField({ + required: true, + initial: false, + label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.actionPoints.label' + }), + countdowns: new fields.BooleanField({ + requireD: true, + initial: false, + label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.countdowns.label' + }) }; } } diff --git a/module/dice/dhRoll.mjs b/module/dice/dhRoll.mjs index c461e14a..c3918a13 100644 --- a/module/dice/dhRoll.mjs +++ b/module/dice/dhRoll.mjs @@ -19,7 +19,7 @@ export default class DHRoll extends Roll { } static async buildConfigure(config = {}, message = {}) { - config.hooks = [...(config.hooks ?? []), '']; + config.hooks = [...this.getHooks(), '']; config.dialog ??= {}; for (const hook of config.hooks) { if (Hooks.call(`${CONFIG.DH.id}.preRoll${hook.capitalize()}`, config, message) === false) return null; @@ -94,6 +94,10 @@ export default class DHRoll extends Roll { config.dialog.configure ??= !(config.event.shiftKey || config.event.altKey || config.event.ctrlKey); } + static getHooks(hooks) { + return hooks ?? []; + } + formatModifier(modifier) { const numTerm = modifier < 0 ? '-' : '+'; return [ @@ -131,3 +135,32 @@ export default class DHRoll extends Roll { return modifierTotal; } } + +export const registerRollDiceHooks = () => { + Hooks.on(`${CONFIG.DH.id}.postRollDuality`, async (config, message) => { + if ( + !game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).hope || + config.roll.type === 'reaction' + ) + return; + + const actor = await fromUuid(config.source.actor), + updates = []; + if (!actor) return; + if (config.roll.isCritical || config.roll.result.duality === 1) updates.push({ type: 'hope', value: 1 }); + if (config.roll.isCritical) updates.push({ type: 'stress', value: -1 }); + if (config.roll.result.duality === -1) updates.push({ type: 'fear', value: 1 }); + + if (updates.length) actor.modifyResource(updates); + + if (!config.roll.hasOwnProperty('success') && !config.targets.length) return; + + const rollResult = config.roll.success || config.targets.some(t => t.hit), + looseSpotlight = !rollResult || config.roll.result.duality === -1; + + if (looseSpotlight && game.combat?.active) { + const currentCombatant = game.combat.combatants.get(game.combat.current?.combatantId); + if (currentCombatant?.actorId == actor.id) ui.combat.setCombatantSpotlight(currentCombatant.id); + } + }); +}; diff --git a/module/dice/dualityRoll.mjs b/module/dice/dualityRoll.mjs index 0f1c51d9..4d0e99a3 100644 --- a/module/dice/dualityRoll.mjs +++ b/module/dice/dualityRoll.mjs @@ -79,7 +79,10 @@ export default class DualityRoll extends D20Roll { return game.i18n.localize(label); } - updateFormula() {} + static getHooks(hooks) { + + return [...(hooks ?? []), 'Duality']; + } createBaseDice() { if ( diff --git a/module/systemRegistration/socket.mjs b/module/systemRegistration/socket.mjs index 0be0a633..d7f79df9 100644 --- a/module/systemRegistration/socket.mjs +++ b/module/systemRegistration/socket.mjs @@ -39,20 +39,16 @@ export const registerSocketHooks = () => { } break; case GMUpdateEvent.UpdateSetting: - if (game.user.isGM) { - await game.settings.set(CONFIG.DH.id, data.uuid, data.update); - } + await game.settings.set(CONFIG.DH.id, data.uuid, data.update); break; case GMUpdateEvent.UpdateFear: - if (game.user.isGM) { - await game.settings.set( - CONFIG.DH.id, - CONFIG.DH.SETTINGS.gameSettings.Resources.Fear, - Math.max(Math.min(data.update, 6), 0) - ); - Hooks.callAll(socketEvent.DhpFearUpdate); - await game.socket.emit(`system.${CONFIG.DH.id}`, { action: socketEvent.DhpFearUpdate }); - } + await game.settings.set( + CONFIG.DH.id, + CONFIG.DH.SETTINGS.gameSettings.Resources.Fear, + Math.max(0, Math.min(game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxFear, data.update)) + ); + /* Hooks.callAll(socketEvent.DhpFearUpdate); + await game.socket.emit(`system.${CONFIG.DH.id}`, { action: socketEvent.DhpFearUpdate }); */ break; } @@ -66,3 +62,22 @@ export const registerSocketHooks = () => { } }); }; + +export const emitAsGM = async (eventName, callback, args) => { + if(!game.user.isGM) { + return new Promise(async (resolve, reject) => { + try { + const response = await game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.GMUpdate, + data: { + action: eventName, + update: args + } + }); + resolve(response); + } catch (error) { + reject(error); + } + }) + } else return callback(args); +} diff --git a/styles/daggerheart.css b/styles/daggerheart.css index 8fd6142e..f15583d2 100755 --- a/styles/daggerheart.css +++ b/styles/daggerheart.css @@ -4069,10 +4069,11 @@ body.theme-light.application.daggerheart .character-sidebar-sheet .experience-va .application.sheet.daggerheart.actor.dh-style.character .window-content { display: grid; grid-template-columns: 275px 1fr; - grid-template-rows: 283px 1fr; + grid-template-rows: auto 1fr; gap: 15px 0; height: 100%; width: 100%; + overflow: auto; } .application.sheet.daggerheart.actor.dh-style.character .window-content .character-sidebar-sheet { grid-row: 1 / span 2; @@ -4313,7 +4314,7 @@ body.theme-light.application.daggerheart .character-sidebar-sheet .experience-va .application.sheet.daggerheart.actor.dh-style.adversary .window-content { display: grid; grid-template-columns: 275px 1fr; - grid-template-rows: 283px 1fr; + grid-template-rows: auto 1fr; gap: 15px 0; height: 100%; width: 100%; diff --git a/templates/dialogs/dice-roll/rollSelection.hbs b/templates/dialogs/dice-roll/rollSelection.hbs index c01b33ba..5c0ba41d 100644 --- a/templates/dialogs/dice-roll/rollSelection.hbs +++ b/templates/dialogs/dice-roll/rollSelection.hbs @@ -1,6 +1,6 @@