diff --git a/css/deltagreen.css b/css/deltagreen.css index ce6d242..a3209fc 100644 --- a/css/deltagreen.css +++ b/css/deltagreen.css @@ -1296,3 +1296,11 @@ body:not(.no-theme) #interface:not(.theme-light) #action-bar .slot.full:hover { .strike { text-decoration: line-through; } + +.settings-menu { + footer { + position: absolute; + left: 10px; + bottom: 10px; + } +} \ No newline at end of file diff --git a/lang/en.json b/lang/en.json index ba0d360..a2a1581 100644 --- a/lang/en.json +++ b/lang/en.json @@ -387,18 +387,27 @@ "DG.Settings.charactersheet.program": "The Program", "DG.Settings.sortskills.name": "Sort Skills By Column?", "DG.Settings.sortskills.hint": "Checked sorts by column. Unchecked sorts by row.", - "DG.Settings.sanityprivate.name": "Keep Sanity Private", - "DG.Settings.sanityprivate.hint": "Hide sanity from players on both character sheet and rolls.", + "DG.Settings.keepSanityPrivate.name": "Keep Sanity Private", + "DG.Settings.keepSanityPrivate.hint": "Hide sanity from players on both character sheet and rolls.", "DG.Settings.improvementroll.name": "Default Skill Improvement Roll", "DG.Settings.improvementroll.hint": " Default 1d4. There have been multiple errata on this, choose which fits best for the pace of your game.", "DG.Settings.improvementroll.1": "Flat +1", "DG.Settings.improvementroll.2": "+1D3%", "DG.Settings.improvementroll.3": "+1D4%", "DG.Settings.improvementroll.4": "+1D4-1%", - "DG.Settings.hypergeometry.name": "Always Show Hypergeometry Section for Players", - "DG.Settings.hypergeometry.hint": "Always show Hypergeometry item section for players, even if they don't have any items of that type.", - "DG.Settings.landscapes.name": "Show Impossible Landscapes Content", - "DG.Settings.landscapes.hint": "Show Impossible Landscapes-specific fields from character sheets.", + "DG.Settings.alwaysShowHypergeometrySectionForPlayers.name": "Always Show Hypergeometry Section for Players", + "DG.Settings.alwaysShowHypergeometrySectionForPlayers.hint": "Always show Hypergeometry item section for players, even if they don't have any items of that type.", + "DG.Settings.showImpossibleLandscapesContent.name": "Show Impossible Landscapes Content", + "DG.Settings.showImpossibleLandscapesContent.hint": "Show Impossible Landscapes-specific fields from character sheets.", + "DG.Settings.automateSanity.name": "Show Impossible Landscapes-specific fields from character sheets.", + "DG.Settings.skillFailure.name": "Auto set skill failure", + "DG.Settings.skillFailure.hint": "", + + "DG.SettingsMenu.automation.name": "Automation Menu", + "DG.SettingsMenu.automation.label": "Automation Menu", + + "DG.SettingsMenu.handler.name": "Handler Settings", + "DG.SettingsMenu.handler.label": "Handler Settings", "DG.Messages.Skillsmark.Marked": "This skill is marked", "DG.Messages.Skillsmark.Tooltip": "See p. 29 Agent's Handbook" diff --git a/module/roll/roll.js b/module/roll/roll.js index b1078f1..a02a969 100644 --- a/module/roll/roll.js +++ b/module/roll/roll.js @@ -1,5 +1,6 @@ /* eslint-disable max-classes-per-file */ import DGUtils from "../other/utility-functions.js"; +import DG from "../config.js"; const { renderTemplate } = foundry.applications.handlebars; @@ -298,7 +299,8 @@ export class DGPercentileRoll extends DGRoll { } const failureMark = !this.isSuccess && this.skillPath - && !foundry.utils.getProperty(this.actor, `${this.skillPath}.failure`); + && !foundry.utils.getProperty(this.actor, `${this.skillPath}.failure`) + && game.settings.get(DG.ID, "skillFailure"); const { renderTemplate } = foundry.applications.handlebars; const html = await renderTemplate( diff --git a/module/settings.js b/module/settings.js index 3860ba6..d4303c5 100644 --- a/module/settings.js +++ b/module/settings.js @@ -1,6 +1,142 @@ import DG from "./config.js"; +const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; + +const SettingForm = class extends HandlebarsApplicationMixin(ApplicationV2) { + constructor() { + super(); + } + + static _namespace; + + static get namespace() { + return this.constructor._namespace + }; + + static get settings() { + return {} + } + + static init() { + const settings = this.settings; + for (const setting of Object.keys(settings)) { + game.settings.register(DG.ID, setting, { + scope: "world", + config: false, + name: game.i18n.localize(`DG.Settings.${setting}.name`), + hint: game.i18n.localize(`DG.Settings.${setting}.hint`), + ...settings[setting], + }); + } + } + + static DEFAULT_OPTIONS = { + tag: "form", + id: `${DG.ID}-setting-form`, + classes: [DG.ID, "settings-menu"], + window: {title: ``, resizable: true}, + position: {width: 500, height: 400}, + actions: {}, + form: { + handler: this.onSubmit, + submitOnChange: false, + closeOnSubmit: false + } + }; + + static PARTS = { + form: { template: `systems/${DG.ID}/templates/settings.hbs` }, + } + + static async onSubmit(event, form, formData) { + event.preventDefault(); + const data = foundry.utils.expandObject(formData.object); + + for (const key in data) { + game.settings.set(DG.ID, key, data[key]); + } + } + + async _prepareContext(_options) { + let context = await super._prepareContext(_options); + context.settings = Object.entries(this.constructor.settings).reduce(function (obj, [key, setting]) { + obj[key] = { + ...setting, + key, + name: `DG.Settings.${key}.name`, + hint: `DG.Settings.${key}.hint`, + value: game.settings.get(DG.ID, key), + isSelect: !!setting.choices, + isNumber: setting.type === Number, + isString: setting.type === String, + isCheckbox: setting.type === Boolean, + }; + return obj; + }, {}); + return context; + } +} + +class AutomationSettings extends SettingForm { + + static _namespace = "automation"; + + static get settings() { + return { + skillFailure: { + default: false, + type: Boolean, + } + }; + } +} + +class HandlerSettings extends SettingForm { + + static _namespace = "handler"; + + static get settings() { + return { + alwaysShowHypergeometrySectionForPlayers: { + requiresReload: true, + type: Boolean, + default: false, + }, + showImpossibleLandscapesContent: { + requiresReload: true, + type: Boolean, + default: true, + }, + keepSanityPrivate: { + requiresReload: true, + type: Boolean, + default: false, + } + }; + } +} + export default function registerSystemSettings() { + game.settings.registerMenu(DG.ID, "automation", { + name: game.i18n.localize(`DG.SettingsMenu.automation.name`), + label: game.i18n.localize(`DG.SettingsMenu.automation.label`), + hint: "", + icon: "fa-solid fa-dice", + type: AutomationSettings, + restricted: true + }); + AutomationSettings.init(); + + game.settings.registerMenu(DG.ID, "handler", { + name: game.i18n.localize(`DG.SettingsMenu.handler.name`), + label: game.i18n.localize(`DG.SettingsMenu.handler.label`), + hint: "", + icon: "fa-solid fa-dice", + type: HandlerSettings, + restricted: true + }); + HandlerSettings.init(); + game.settings.register("deltagreen", "characterSheetStyle", { name: game.i18n.localize("DG.Settings.charactersheet.name"), hint: game.i18n.localize("DG.Settings.charactersheet.hint"), @@ -31,16 +167,6 @@ export default function registerSystemSettings() { default: false, }); - game.settings.register("deltagreen", "keepSanityPrivate", { - name: game.i18n.localize("DG.Settings.sanityprivate.name"), - hint: game.i18n.localize("DG.Settings.sanityprivate.hint"), - scope: "world", - config: true, - requiresReload: true, - type: Boolean, - default: false, - }); - game.settings.register("deltagreen", "skillImprovementFormula", { name: game.i18n.localize("DG.Settings.improvementroll.name"), hint: game.i18n.localize("DG.Settings.improvementroll.hint"), @@ -55,30 +181,6 @@ export default function registerSystemSettings() { }, }); - game.settings.register( - "deltagreen", - "alwaysShowHypergeometrySectionForPlayers", - { - name: game.i18n.localize("DG.Settings.hypergeometry.name"), - hint: game.i18n.localize("DG.Settings.hypergeometry.hint"), - scope: "world", - config: true, - requiresReload: true, - type: Boolean, - default: false, - }, - ); - - game.settings.register("deltagreen", "showImpossibleLandscapesContent", { - name: game.i18n.localize("DG.Settings.landscapes.name"), - hint: game.i18n.localize("DG.Settings.landscapes.hint"), - scope: "world", - config: true, - requiresReload: true, - type: Boolean, - default: true, - }); - // obsolete - will be removed at some point game.settings.register("deltagreen", "characterSheetFont", { name: "World Font Choice", diff --git a/templates/settings.hbs b/templates/settings.hbs new file mode 100644 index 0000000..f634d2d --- /dev/null +++ b/templates/settings.hbs @@ -0,0 +1,25 @@ +
+ {{#each settings as |setting|}} +
+ + {{#if setting.isSelect}} + + {{else if setting.isCheckbox}} + + {{else if setting.isNumber}} + + {{else if setting.isString}} + + {{/if}} + {{#if setting.hint}} +

{{localize setting.hint}}

+ {{/if}} +
+ {{/each}} + + +
\ No newline at end of file