Skip to content

Commit

Permalink
work in progress on moving saves customisation into a settings menu s…
Browse files Browse the repository at this point in the history
…o I can have validation and better control

orffen#69
  • Loading branch information
DC23 committed Nov 26, 2024
1 parent 1c41b18 commit 9096a70
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 92 deletions.
7 changes: 4 additions & 3 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,9 @@
"BASICFANTASYRPG.EffectEdit": "Edit Effect",
"BASICFANTASYRPG.EffectDelete": "Delete Effect",

"BASICFANTASYRPG.AutoRollTokenHP.name": "Automatically Roll Token HP",
"BASICFANTASYRPG.AutoRollTokenHP.hint": "Based on HD value. If this setting is turned off, HP will be set to TODO WORK OUT WHAT",

"BASICFANTASYRPG.Settings.SavesMenu.name": "Edit Saving Throw Names",
"BASICFANTASYRPG.Settings.SavesMenu.label": "Saving Throw Settings",
"BASICFANTASYRPG.Settings.SavesMenu.hint": "",
"BASICFANTASYRPG.SaveName.hint": "Custom name for this saving throw. The same name is used for all players."

}
17 changes: 17 additions & 0 deletions module/helpers/settings.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// not the greatest approach, but
export function objectsShallowEqual (obj1, obj2) {
const entries1 = Object.entries(obj1)
const entries2 = Object.entries(obj2)

if (entries1.length !== entries2.length) {
return false
}

for (let [key, value] of entries1) {
if (obj2[key] !== value) {
return false
}
}

return true
}
92 changes: 92 additions & 0 deletions module/settings/saves-settings.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// import { Helpers } from './helpers.mjs'
import { objectsShallowEqual } from '../helpers/settings.mjs'
import { SYSTEM_ID, SETTINGS } from './settings.mjs'

// Helper array of IDs we'll use in a few places
const saves = ['death', 'wands', 'paralysis', 'breath', 'spells']

export function registerSavesSettings () {
// The settings menu
game.settings.registerMenu(SYSTEM_ID, SETTINGS.SAVES_MENU, {
name: 'BASICFANTASYRPG.Settings.SavesMenu.name',
label: 'BASICFANTASYRPG.Settings.SavesMenu.label',
hint: 'BASICFANTASYRPG.Settings.SavesMenu.hint',
icon: 'fas fa-cog',
type: SavesSettings,
restricted: true // GM-only
})

// the settings object
game.settings.register(SYSTEM_ID, SETTINGS.SAVES_SETTINGS, {
scope: 'world',
config: false,
type: Object,
default: SavesSettings.defaultSaves
})
}

class SavesSettings extends FormApplication {
static #defaultSaves = null
static get defaultSaves () {
if (!SavesSettings.#defaultSaves) {
SavesSettings.#defaultSaves = {}
saves.forEach(s => {
SavesSettings.#defaultSaves[s] = game.i18n.localize(
`BASICFANTASYRPG.Save${s.capitalize()}`
)
})
}
return SavesSettings.#defaultSaves
}

static get defaultOptions () {
return foundry.utils.mergeObject(super.defaultOptions, {
popOut: true,
width: 400,
template: `systems/${SYSTEM_ID}/templates/settings/saves-settings.hbs`,
id: SETTINGS.SAVES_MENU,
title: 'BASICFANTASYRPG.Settings.SavesMenu.name'
})
}

getData () {
const initialValues = game.settings.get(SYSTEM_ID, SETTINGS.SAVES_SETTINGS)
// repack the current saves names into id, label and values for the form
const data = {}
saves.forEach((v, i) => {
data[i] = {
id: v,
label: SavesSettings.defaultSaves[v],
value: initialValues[v]
}
})
return data
}

_updateObject (event, formData) {
const data = foundry.utils.expandObject(formData)
const current = game.settings.get(SYSTEM_ID, SETTINGS.SAVES_SETTINGS)

if (!objectsShallowEqual(data, current)) {
game.settings.set(SYSTEM_ID, SETTINGS.SAVES_SETTINGS, data)
SettingsConfig.reloadConfirm({ world: true })
}
}

activateListeners (html) {
super.activateListeners(html)
html.on('click', '[data-action=reset]', this._handleResetButtonClicked)
}

async _handleResetButtonClicked (event) {
console.log('BFRPG | Reset save names to default values')
saves.forEach(id => {
const element = $(event.delegateTarget).find(`[name=${id}]`)
if (element && element.length > 0) {
element[0].value = game.i18n.localize(
`BASICFANTASYRPG.Save${id.capitalize()}`
)
}
})
}
}
109 changes: 20 additions & 89 deletions module/settings/settings.mjs
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import { BASICFANTASYRPG } from "../helpers/config.mjs"
import { BASICFANTASYRPG } from '../helpers/config.mjs'
import { registerSavesSettings } from './saves-settings.mjs'

/**
* pseudo-enum to make setting ID references less error prone
*/
export const SETTINGS = {
// AUTO_ROLL_TOKEN_HP: 'autoRollTokenHP',
// use the saves keys as the setting ID to make retrieval easy.
// AUTO_ROLL_TOKEN_HP: 'autoRollTokenHP',
// use the saves keys as the setting ID to make retrieval easy.
// So long as the system.key is unique, it's fine.
SAVE_DEATH_NAME: 'death',
SAVE_WANDS_NAME: 'wands',
SAVE_PARALYSIS_NAME: 'paralysis',
SAVE_BREATH_NAME: 'breath',
SAVE_SPELLS_NAME: 'spells',

SAVES_MENU: 'savesMenu',
SAVES_SETTINGS: 'savesSettings'
}

// Use this internally for now. Refactoring the whole system is too big a job!
Expand All @@ -22,103 +26,30 @@ export const SYSTEM_ID = 'basicfantasyrpg'
* non-GM users. We iterate the array in the renderSettingsConfig
* hook and remove those settings from the DOM when required.
* This workaround is necessary because in Foundry v12, a restricted
* flag to show a setting to GM users is only supported for a setting
* flag to show a setting to GM users is only supported for a setting
* menu, not a setting itself.
*/
const GM_ONLY_SETTINGS = [
SETTINGS.SAVE_DEATH_NAME,
SETTINGS.SAVE_WANDS_NAME,
SETTINGS.SAVE_PARALYSIS_NAME,
SETTINGS.SAVE_BREATH_NAME,
SETTINGS.SAVE_SPELLS_NAME,
// SETTINGS.SAVE_DEATH_NAME,
// SETTINGS.SAVE_WANDS_NAME,
// SETTINGS.SAVE_PARALYSIS_NAME,
// SETTINGS.SAVE_BREATH_NAME,
// SETTINGS.SAVE_SPELLS_NAME
]

Hooks.on('renderSettingsConfig', (app, [html], context) => {
if (game.user.isGM) return
if (game.user.isGM) return

GM_ONLY_SETTINGS.forEach(id => {
html.querySelector(`.form-group[data-setting-id="${SYSTEM_ID}.${id}"]`)?.remove()
})
GM_ONLY_SETTINGS.forEach(id => {
html
.querySelector(`.form-group[data-setting-id="${SYSTEM_ID}.${id}"]`)
?.remove()
})
})


export function registerSettings () {
/**
* If we have any settings submenus, they'd be defined in separate files and called from here.
*/

/*
Disabled for now based on https://discord.com/channels/735808783493890058/1307906023444582430/1309772596103086081
Will delete later once confirmed that it's the wrong direction.
game.settings.register(SYSTEM_ID, SETTINGS.AUTO_ROLL_TOKEN_HP, {
name: 'BASICFANTASYRPG.AutoRollTokenHP.name',
hint: 'BASICFANTASYRPG.AutoRollTokenHP.hint',
scope: 'world',
config: true,
type: Boolean,
default: true,
requiresReload: false,
})
*/

/**
* Saving throw customisation.
* If we get too many settings, these could be broken out into a submenu.
* It's more coding work, but keeps things together for the users.
*/
// Death Ray or Poison
game.settings.register(SYSTEM_ID, SETTINGS.SAVE_DEATH_NAME, {
name: 'BASICFANTASYRPG.SaveDeath',
hint: 'BASICFANTASYRPG.SaveName.hint',
scope: 'world',
config: true,
type: String,
default: game.i18n.localize('BASICFANTASYRPG.SaveDeath'),
requiresReload: true, // I assume this will need a reload to ensure everything is re-rendered
})

// "BASICFANTASYRPG.SaveWands": "Magic Wands",
game.settings.register(SYSTEM_ID, SETTINGS.SAVE_WANDS_NAME, {
name: 'BASICFANTASYRPG.SaveWands',
hint: 'BASICFANTASYRPG.SaveName.hint',
scope: 'world',
config: true,
type: String,
default: game.i18n.localize('BASICFANTASYRPG.SaveWands'),
requiresReload: true, // I assume this will need a reload to ensure everything is re-rendered
})

// "BASICFANTASYRPG.SaveParalysis": "Paralysis or Petrify",
game.settings.register(SYSTEM_ID, SETTINGS.SAVE_PARALYSIS_NAME, {
name: 'BASICFANTASYRPG.SaveParalysis',
hint: 'BASICFANTASYRPG.SaveName.hint',
scope: 'world',
config: true,
type: String,
default: game.i18n.localize('BASICFANTASYRPG.SaveParalysis'),
requiresReload: true, // I assume this will need a reload to ensure everything is re-rendered
})

// "BASICFANTASYRPG.SaveBreath": "Dragon Breath",
game.settings.register(SYSTEM_ID, SETTINGS.SAVE_BREATH_NAME, {
name: 'BASICFANTASYRPG.SaveBreath',
hint: 'BASICFANTASYRPG.SaveName.hint',
scope: 'world',
config: true,
type: String,
default: game.i18n.localize('BASICFANTASYRPG.SaveBreath'),
requiresReload: true, // I assume this will need a reload to ensure everything is re-rendered
})

// "BASICFANTASYRPG.SaveSpells": "Rods, Staves, and Spells",
game.settings.register(SYSTEM_ID, SETTINGS.SAVE_SPELLS_NAME, {
name: 'BASICFANTASYRPG.SaveSpells',
hint: 'BASICFANTASYRPG.SaveName.hint',
scope: 'world',
config: true,
type: String,
default: game.i18n.localize('BASICFANTASYRPG.SaveSpells'),
requiresReload: true, // I assume this will need a reload to ensure everything is re-rendered
})

registerSavesSettings()
}
25 changes: 25 additions & 0 deletions templates/settings/saves-settings.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{{#*inline "savePartial"}}
<div class="form-row flexrow">
<label for="{{id}}">{{label}}:</label>
<input name="{{id}}" required=true value="{{value}}" />
</div>
{{/inline}}

{{log this}}
<form class="form-group flexcol">
<fieldset>
<legend>{{localize "BASICFANTASYRPG.Settings.SavesMenu.name"}}:</legend>
{{#each this}}
{{> savePartial}}
{{/each}}
</fieldset>

<footer class="sheet-footer flexrow button-container">
<button class="reset-all" type="button" name="reset" data-action="reset">
<i class="fa-solid fa-undo"></i> {{localize "SETTINGS.Reset"}}
</button>
<button type="submit" name="submit">
<i class="fa-solid fa-save"></i> {{localize "SETTINGS.Save"}}
</button>
</footer>
</form>

0 comments on commit 9096a70

Please sign in to comment.