Files
foundryvtt-drag-ruler/js/settings.js
T

322 lines
9.8 KiB
JavaScript

import {
availableSpeedProviders,
currentSpeedProvider,
getDefaultSpeedProvider,
updateSpeedProvider,
} from "./api.js";
import {SpeedProvider} from "./speed_provider.js";
import {early_isGM} from "./util.js";
export const settingsKey = "drag-ruler";
export const RightClickAction = Object.freeze({
CREATE_WAYPOINT: 0,
DELETE_WAYPOINT: 1,
ABORT_DRAG: 2,
});
function delayedReload() {
window.setTimeout(() => location.reload(), 500);
}
export function registerSettings() {
game.settings.register(settingsKey, "dataVersion", {
scope: "world",
config: false,
type: String,
default: "fresh install",
});
game.settings.register(settingsKey, "clientDataVersion", {
scope: "client",
config: false,
type: String,
default: "fresh install",
});
game.settings.register(settingsKey, "rightClickAction", {
name: "drag-ruler.settings.rightClickAction.name",
hint: "drag-ruler.settings.rightClickAction.hint",
config: true,
type: Number,
default: RightClickAction.DELETE_WAYPOINT,
choices: {
0: "drag-ruler.settings.rightClickAction.choices.create",
1: "drag-ruler.settings.rightClickAction.choices.delete",
2: "drag-ruler.settings.rightClickAction.choices.cancel",
},
});
game.settings.register(settingsKey, "autoStartMeasurement", {
name: "drag-ruler.settings.autoStartMeasurement.name",
hint: "drag-ruler.settings.autoStartMeasurement.hint",
scope: "client",
config: true,
type: Boolean,
default: true,
});
game.settings.register(settingsKey, "useGridlessRaster", {
name: "drag-ruler.settings.useGridlessRaster.name",
hint: "drag-ruler.settings.useGridlessRaster.hint",
scope: "client",
config: true,
type: Boolean,
default: true,
});
game.settings.register(settingsKey, "alwaysShowSpeedForPCs", {
name: "drag-ruler.settings.alwaysShowSpeedForPCs.name",
hint: "drag-ruler.settings.alwaysShowSpeedForPCs.hint",
scope: "world",
config: true,
type: Boolean,
default: true,
});
game.settings.register(settingsKey, "showGMRulerToPlayers", {
name: "drag-ruler.settings.showGMRulerToPlayers.name",
hint: "drag-ruler.settings.showGMRulerToPlayers.hint",
scope: "world",
config: true,
type: Boolean,
default: true,
});
game.settings.register(settingsKey, "enableMovementHistory", {
name: "drag-ruler.settings.enableMovementHistory.name",
hint: "drag-ruler.settings.enableMovementHistory.hint",
scope: "world",
config: true,
type: Boolean,
default: true,
});
if (game.modules.get("routinglib")?.active) {
game.settings.register(settingsKey, "allowPathfinding", {
name: "drag-ruler.settings.allowPathfinding.name",
hint: "drag-ruler.settings.allowPathfinding.hint",
scope: "world",
config: true,
type: Boolean,
default: false,
onChange: delayedReload,
});
game.settings.register(settingsKey, "autoPathfinding", {
name: "drag-ruler.settings.autoPathfinding.name",
hint: "drag-ruler.settings.autoPathfinding.hint",
scope: "client",
config: early_isGM() || game.settings.get(settingsKey, "allowPathfinding"),
type: Boolean,
default: false,
});
}
game.settings.register(settingsKey, "lastTerrainRulerHintTime", {
config: false,
type: Number,
default: 0,
});
game.settings.register(settingsKey, "neverShowTerrainRulerHint", {
config: false,
type: Boolean,
default: false,
});
// This setting will be modified by the api if modules register to it
game.settings.register(settingsKey, "speedProvider", {
scope: "world",
config: false,
type: String,
default: getDefaultSpeedProvider(),
onChange: updateSpeedProvider,
});
game.settings.registerMenu(settingsKey, "speedProviderSettings", {
name: "drag-ruler.settings.speedProviderSettings.name",
hint: "drag-ruler.settings.speedProviderSettings.hint",
label: "drag-ruler.settings.speedProviderSettings.button",
icon: "fas fa-tachometer-alt",
type: SpeedProviderSettings,
restricted: false,
});
}
class SpeedProviderSettings extends FormApplication {
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
id: "drag-ruler-speed-provider-settings",
title: game.i18n.localize("drag-ruler.settings.speedProviderSettings.windowTitle"),
template: "modules/drag-ruler/templates/speed_provider_settings.html",
width: 600,
});
}
getData(options = {}) {
const data = {};
data.isGM = game.user.isGM;
const selectedProvider = currentSpeedProvider.id;
// Insert all speed providers into the template data
data.providers = Object.values(availableSpeedProviders).map(speedProvider => {
const provider = {};
provider.id = speedProvider.id;
provider.hasSettings = speedProvider instanceof SpeedProvider;
if (provider.hasSettings) provider.settings = enumerateProviderSettings(speedProvider);
let dotPosition = provider.id.indexOf(".");
if (dotPosition === -1) dotPosition = provider.id.length;
const type = provider.id.substring(0, dotPosition);
const id = provider.id.substring(dotPosition + 1);
if (type === "native") {
provider.selectTitle = game.i18n.localize(
"drag-ruler.settings.speedProviderSettings.speedProvider.choices.native",
);
} else {
let name;
if (type === "module") {
name = game.modules.get(id).data.title;
} else {
name = game.system.data.title;
}
provider.selectTitle = game.i18n.format(
`drag-ruler.settings.speedProviderSettings.speedProvider.choices.${type}`,
{name},
);
}
provider.isSelected = provider.id === selectedProvider;
return provider;
});
data.selectedProviderName = data.providers.find(provider => provider.isSelected).selectTitle;
data.providerSelection = {
id: "speedProvider",
name: game.i18n.localize("drag-ruler.settings.speedProviderSettings.speedProvider.name"),
hint: game.i18n.localize("drag-ruler.settings.speedProviderSettings.speedProvider.hint"),
type: String,
choices: data.providers.reduce((choices, provider) => {
choices[provider.id] = provider.selectTitle;
return choices;
}, {}),
value: selectedProvider,
isCheckbox: false,
isSelect: true,
isRange: false,
};
return data;
}
async _updateObject(event, formData) {
const selectedSpeedProvider = game.user.isGM
? formData.speedProvider
: game.settings.get(settingsKey, "speedProvider");
for (let [key, value] of Object.entries(formData)) {
// Check if this is color, convert the value to an integer
const splitKey = key.split(".", 3);
if (splitKey[0] !== "native") splitKey.shift();
if (splitKey.length >= 2 && splitKey[1] == "color") {
value = parseInt(value.substring(1), 16);
}
// Don't change settings for speed providers that aren't currently active
if (key !== "speedProvider" && !key.startsWith(selectedSpeedProvider)) continue;
// Get the key for the current setting
let setting;
if (key === "speedProvider") setting = "speedProvider";
else setting = `speedProviders.${key}`;
// Get the old setting value
const oldValue = game.settings.get(settingsKey, setting);
// Only update the setting if it has been changed (this leaves the default in place if it hasn't been touched)
if (value !== oldValue) game.settings.set(settingsKey, setting, value);
}
// Activate the configured speed provider
updateSpeedProvider();
}
activateListeners(html) {
super.activateListeners(html);
html.find("select[name=speedProvider]").change(this.onSpeedProviderChange.bind(this));
}
onSpeedProviderChange(event) {
// Hide all module settings
document
.querySelectorAll(".drag-ruler-provider-settings")
.forEach(element => (element.style.display = "none"));
// Show the settings block for the currently selected module
document.getElementById(`drag-ruler.provider.${event.currentTarget.value}`).style.display = "";
// Recalculate window height
this.element[0].style.height = null;
this.position.height = undefined;
}
}
function toDomHex(value) {
const hex = value.toString(16);
return "#" + "0".repeat(Math.max(0, 6 - hex.length)) + hex;
}
function enumerateProviderSettings(provider) {
const colorSettings = [];
const unreachableColor = {
id: "unreachable",
name: "drag-ruler.settings.speedProviderSettings.color.unreachable.name",
};
// Resolve settings for the colors
for (const color of provider.colors.concat([unreachableColor])) {
// Localize the name, if avaliable. If no name is available use the id as name
const colorName = color.name ? game.i18n.localize(color.name) : color.id;
let hint;
if (color === unreachableColor)
hint = game.i18n.localize("drag-ruler.settings.speedProviderSettings.color.unreachable.hint");
else
hint = game.i18n.format("drag-ruler.settings.speedProviderSettings.color.hint", {colorName});
colorSettings.push({
id: `${provider.id}.color.${color.id}`,
name: game.i18n.format("drag-ruler.settings.speedProviderSettings.color.name", {colorName}),
hint: hint,
type: Number,
value: toDomHex(
game.settings.get(settingsKey, `speedProviders.${provider.id}.color.${color.id}`),
),
isCheckbox: false,
isSelect: false,
isRange: false,
isColor: true,
});
}
// Prepare regular settings
const settings = [];
for (const setting of provider.settings) {
try {
if (setting.scope === "world" && !game.user.isGM) continue;
const s = duplicate(setting);
s.id = `${provider.id}.setting.${s.id}`;
s.name = game.i18n.localize(s.name);
s.hint = game.i18n.localize(s.hint);
s.value = provider.getSetting(setting.id);
s.type = setting.type instanceof Function ? setting.type.name : "String";
s.isCheckbox = setting.type === Boolean;
s.isSelect = s.choices !== undefined;
s.isRange = setting.type === Number && s.range;
s.isColor = false;
settings.push(s);
} catch (e) {
console.warn(
`Drag Ruler | The following error occured while rendering setting "${setting.id}" of module/system "${this.id}. It won't be displayed.`,
);
console.error(e);
}
}
return settings.concat(colorSettings);
}