Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ If you would like to create a module that supplies its own sheet out of the box

```js
Hooks.once('pbtaSheetConfig', () => {
// Disable the sheet config form.
game.settings.set('pbta', 'sheetConfigOverride', true);
// Define custom tags.
game.pbta.tagConfigOverride = {
// Tags available to any actor and item
Expand Down
7 changes: 0 additions & 7 deletions src/module/forms/sheet-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,11 @@ export class PbtaSettingsConfigDialog extends FormApplication {

/* -------------------------------------------- */

get sheetOverriden() {
return game.settings.get("pbta", "sheetConfigOverride");
}

/* -------------------------------------------- */

/** @override */
async getData(options) {
const sheetConfig = game.settings.get("pbta", "sheetConfig") || {};
return {
...foundry.utils.deepClone(sheetConfig),
sheetConfigOverride: this.sheetOverriden,
tomlString: sheetConfig.tomlString || ""
};
}
Expand Down
181 changes: 81 additions & 100 deletions src/module/pbta.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ globalThis.pbta = {
utils
};

Hooks.once("init", async function () {
Hooks.once("init", () => {
globalThis.pbta = game.pbta = Object.assign(game.system, globalThis.pbta);

CONFIG.ui.combat = applications.combat.PbtACombatTracker;
Expand Down Expand Up @@ -104,27 +104,32 @@ Hooks.once("init", async function () {
});

Hooks.on("i18nInit", () => {
const activeModules = [...game.modules.entries()].filter(([key, m]) => m.active && m.flags[key]?.["pbta-override"]);

if (activeModules.length > 1 && game.user.isGM) {
const names = activeModules.map(([key, m]) => m.name).join(", ");
ui.notifications.warn(game.i18n.format("PBTA.Warnings.TooManyModules", { names }));
}
game.pbta.moduleConfig = activeModules.length > 0;

registerSettings();

// Build out character data structures.
const pbtaSettings = game.settings.get("pbta", "sheetConfig");

// Retrieve overridden config, if enabled.
if (pbtaSettings?.overridden && game.settings.get("pbta", "sheetConfigOverride")) {
if (pbtaSettings.overridden && game.pbta.moduleConfig) {
game.pbta.sheetConfig = pbtaSettings.overridden;
} else if (pbtaSettings?.computed) {
// Otherwise, retrieve computed config.
} else if (pbtaSettings.computed) {
game.pbta.sheetConfig = utils.convertSheetConfig(pbtaSettings.computed);
} else {
// Fallback to empty config.
game.pbta.sheetConfig = pbtaSettings;
}
});

/**
* This function runs after game data has been requested and loaded from the servers, so documents exist
*/
Hooks.once("setup", function () {
Hooks.once("setup", () => {
// Localize CONFIG objects once up-front
const toLocalize = [];
for (let o of toLocalize) {
Expand All @@ -134,100 +139,12 @@ Hooks.once("setup", function () {
}, {});
}

if (game.user.isGM) {
Hooks.on("renderSettings", (app, html) => {
const header = document.createElement("h2");
header.innerText = game.i18n.localize("Powered by the Apocalypse");

const pbtaSettings = document.createElement("div");
html.find("#settings-game")?.after(header, pbtaSettings);

const buttons = [
{
action: (ev) => {
ev.preventDefault();
let menu = game.settings.menus.get("pbta.sheetConfigMenu");
let app = new menu.type();
app.render(true);
},
iconClasses: ["fas", "fa-file-alt"],
label: "PBTA.Settings.sheetConfig.label"
},
{
action: (ev) => {
ev.preventDefault();
window.open("https://asacolips.gitbook.io/pbta-system/", "pbtaHelp", "width=1032,height=720");
},
iconClasses: ["fas", "fa-question-circle"],
label: "PBTA.Settings.button.help"
}
].map(({ action, iconClasses, label }) => {
const button = document.createElement("button");
button.type = "button";

const icon = document.createElement("i");
icon.classList.add(...iconClasses);

button.append(icon, game.i18n.localize(label));

button.addEventListener("click", action);

return button;
});

pbtaSettings.append(...buttons);
});
if (!game.modules.get("babele")?.active) {
utils.getPlaybooks();
}
});

Hooks.once("ready", async function () {
// Override sheet config.
if (game.user.isGM) {
// Force sheet config override off, unless a module changes it.
await game.settings.set("pbta", "sheetConfigOverride", false);

// Allow modules to override the sheet config.
Hooks.callAll("pbtaSheetConfig");

// @todo find something better than this timeout hack.
const timeout = 1000;
setTimeout(() => {
// Retrieve the previous configuration.
let existingConfig = game.settings.get("pbta", "sheetConfig") ?? {};
// @todo hack to fix the old the default value. Remove in a future update.
if (typeof existingConfig !== "object") {
existingConfig = {};
}
// If a module enabled the override, assign it to the config so that player
// clients can use it without the GM being logged in.
if (game.settings.get("pbta", "sheetConfigOverride")) {
existingConfig.overridden = game.pbta.sheetConfig;
game.settings.set("pbta", "sheetConfig", existingConfig);
} else if (existingConfig?.overridden) {
// Otherwise, delete the override config.

// If not tomlString exists, delete the config outright to prevent
// it from being malformed.
if (!existingConfig?.tomlString) {
ui.notifications.info(game.i18n.localize("PBTA.Messages.sheetConfig.overrideRemoved"));
existingConfig = null;
} else {
// Otherwise, restore the previous config.

// Delete overrides.
delete existingConfig.overridden;
delete existingConfig.computed;
// Restore computed config and reapply.
existingConfig.computed = utils.parseTomlString(existingConfig.tomlString);
game.pbta.sheetConfig = utils.convertSheetConfig(existingConfig.computed);
utils.applyActorTemplates(true);
ui.notifications.info(game.i18n.localize("PBTA.Messages.sheetConfig.previousSettingRestored"));
}
game.settings.set("pbta", "sheetConfig", existingConfig);
}
}, timeout);
}

Hooks.once("ready", () => {
// Wait to register hotbar drop hook on ready so that modules could register earlier if they want to
Hooks.on("hotbarDrop", (bar, data, slot) => {
if (["Item"].includes(data.type)) {
Expand All @@ -236,8 +153,26 @@ Hooks.once("ready", async function () {
}
});

if (!(game.modules.get("babele")?.active && game.i18n.lang !== "en")) {
utils.getPlaybooks();
if (game.user.isGM) {
Hooks.callAll("pbta.sheetConfig");
let existingConfig = game.settings.get("pbta", "sheetConfig") ?? {};
const { overridden, tomlString } = existingConfig;
if (game.pbta.moduleConfig) {
existingConfig.overridden = game.pbta.sheetConfig;
} else if (overridden) {
if (!tomlString) {
ui.notifications.info(game.i18n.localize("PBTA.Messages.sheetConfig.overrideRemoved"));
existingConfig = {};
} else {
delete existingConfig.overridden;

existingConfig.computed = utils.parseTomlString(existingConfig.tomlString);
game.pbta.sheetConfig = utils.convertSheetConfig(existingConfig.computed);
utils.applyActorTemplates(true);
ui.notifications.info(game.i18n.localize("PBTA.Messages.sheetConfig.previousSettingRestored"));
}
}
game.settings.set("pbta", "sheetConfig", existingConfig);
}

// Apply structure to actor types.
Expand Down Expand Up @@ -277,6 +212,52 @@ Hooks.on("renderChatMessage", (data, html, options) => {

Hooks.on("renderChatLog", (app, html, data) => documents.ItemPbta.chatListeners(html));
Hooks.on("renderChatPopout", (app, html, data) => documents.ItemPbta.chatListeners(html));
Hooks.on("renderSettings", (app, html) => {
if (!game.user.isGM) return;
const header = document.createElement("h2");
header.innerText = game.i18n.localize("Powered by the Apocalypse");

const pbtaSettings = document.createElement("div");
html.find("#settings-game")?.after(header, pbtaSettings);

const buttons = [
{
action: (ev) => {
ev.preventDefault();
window.open("https://asacolips.gitbook.io/pbta-system/", "pbtaHelp", "width=1032,height=720");
},
iconClasses: ["fas", "fa-question-circle"],
label: "PBTA.Settings.button.help"
}
];
if (!game.pbta.moduleConfig) {
buttons.unshift({
action: (ev) => {
ev.preventDefault();
let menu = game.settings.menus.get("pbta.sheetConfigMenu");
let app = new menu.type();
app.render(true);
},
iconClasses: ["fas", "fa-file-alt"],
label: "PBTA.Settings.sheetConfig.label"
});
}
const formattedButtons = buttons.map(({ action, iconClasses, label }) => {
const button = document.createElement("button");
button.type = "button";

const icon = document.createElement("i");
icon.classList.add(...iconClasses);

button.append(icon, game.i18n.localize(label));

button.addEventListener("click", action);

return button;
});

pbtaSettings.append(...formattedButtons);
});

/**
* Configure explicit lists of attributes that are trackable on the token HUD and in the combat tracker.
Expand Down
29 changes: 11 additions & 18 deletions src/module/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@ import { PbtaTagConfigDialog } from "./forms/tag-config.js";
* Register all of the system's settings.
*/
export function registerSettings() {
game.settings.registerMenu("pbta", "sheetConfigMenu", {
name: game.i18n.localize("PBTA.Settings.sheetConfig.name"),
label: game.i18n.localize("PBTA.Settings.sheetConfig.title"),
hint: game.i18n.localize("PBTA.Settings.sheetConfig.hint"),
icon: "fas fa-file-alt", // A Font Awesome icon used in the submenu button
type: PbtaSettingsConfigDialog, // A FormApplication subclass which should be created
restricted: true, // Restrict this submenu to gamemaster only?
scope: "world"
});

if (!game.pbta.moduleConfig) {
game.settings.registerMenu("pbta", "sheetConfigMenu", {
name: game.i18n.localize("PBTA.Settings.sheetConfig.name"),
label: game.i18n.localize("PBTA.Settings.sheetConfig.title"),
hint: game.i18n.localize("PBTA.Settings.sheetConfig.hint"),
icon: "fas fa-file-alt", // A Font Awesome icon used in the submenu button
type: PbtaSettingsConfigDialog, // A FormApplication subclass which should be created
restricted: true, // Restrict this submenu to gamemaster only?
scope: "world"
});
}
game.settings.registerMenu("pbta", "tagConfigMenu", {
name: game.i18n.localize("PBTA.Settings.tagConfig.name"),
label: game.i18n.localize("PBTA.Settings.tagConfig.label"),
Expand Down Expand Up @@ -125,14 +126,6 @@ export function registerSettings() {
default: {}
});

game.settings.register("pbta", "sheetConfigOverride", {
name: "Override PBTA Sheet Config",
scope: "world",
config: false,
type: Boolean,
default: false
});

game.settings.register("pbta", "tagConfig", {
name: "PBTA Tag Config",
scope: "world",
Expand Down
4 changes: 0 additions & 4 deletions src/templates/dialog/sheet-config.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
<i class="fas fa-question-circle"></i> {{localize "PBTA.Settings.button.help"}}
</button>

{{#if sheetConfigOverride}}
<div class="notification error">{{localize "PBTA.Settings.sheetConfig.sheetConfigDisabledModule"}}</div>
{{else}}
<section class="pbta-sheet-config-editor">
<textarea name="tomlString" class="pbta-sheet-config">
{{~" "}}{{{tomlString}}}{{" "~}}
Expand All @@ -24,5 +21,4 @@
<i class="fas fa-sync"></i> {{localize 'PERMISSION.Reset'}}
</button>
</div>
{{/if}}
</form>
1 change: 1 addition & 0 deletions src/yaml/lang/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ PBTA:
MissingTargetWarn: "Your controlled actor '{actor}' does not have an item with name '{name}'."
MultipleTargetsWarn: "Your controlled actor '{actor}' has more than one item with name '{name}'. The first match will be chosen."
TagDeprecation: "Tags as items have been deprecated, use the Tag Configuration menu on the game settings to create your tags."
TooManyModules: "You have more than one module attempting to override PbtA's sheet config: {names}"
UnlinkedToken:
Equipment: "Equipment cannot be rearranged while this token is not linked to an actor."
Moves: "Moves cannot be rearranged while this token is not linked to an actor."
Expand Down