diff --git a/module.json b/module.json index a154adc..7910ced 100644 --- a/module.json +++ b/module.json @@ -14,8 +14,7 @@ "/scripts/creature-aide.js" ], "styles": [ - "/styles/creature-aide.css", - "/styles/action-dialog-app.css" + "/styles/creature-aide.css" ], "includes": [ "module.json" @@ -55,6 +54,7 @@ "url": "https://github.com/vtt-lair/simbuls-creature-aide", "manifest": "https://github.com/vtt-lair/simbuls-creature-aide/releases/latest/download/module.json", "download": "https://github.com/vtt-lair/simbuls-creature-aide/releases/download/v1.0.0/simbuls-creature-aide-v1.0.0.zip", + "changelog": "https://github.com/vtt-lair/simbuls-creature-aide/blob/main/CONTRIBUTORS.md", "relationships": { "systems": [ { @@ -65,6 +65,15 @@ "verified": "2.0.2" } } + ], + "requires": [ + { + "id": "simbuls-athenaeum", + "type": "module", + "compatibility": { + "verified": "1.0.0" + } + } ] }, "compatibility": { diff --git a/scripts/apps/action-dialog.js b/scripts/apps/action-dialog.js deleted file mode 100644 index 4fbe9c7..0000000 --- a/scripts/apps/action-dialog.js +++ /dev/null @@ -1,166 +0,0 @@ -import { logger } from '../logger.js'; -import { MODULE } from '../module.js'; - -/** - * Simple form app that allows you to list abilities for a combatant - * - * options = { - * action, bonus, reaction, legendary, lair, special - * } - */ -export class ActionDialog extends Dialog { - /** @override */ - constructor(combatants, options = { action : true, bonus : true, reaction : true, legendary : true, lair : true, special : true, id: ActionDialog.DEFAULT_ID }){ - /* - Build Options - */ - super(options); - foundry.utils.mergeObject(this.options, options); - - /* - Build Data - */ - this.data = {}; - this.data.title = options?.title ?? "Action Dialog"; - this.data.buttons = { - close: { label: MODULE.format("Close"), callback: ActionDialog.storePosition} - }; - this.data.default = "close"; - this.data.combatants = combatants; - mergeObject(this.position, ActionDialog._lastPosition.get(this.options.id) ?? {}); - } - - static DEFAULT_ID = 'creature-aide-action-dialog'; - static _lastPosition = new Map(); - - static storePosition(html) { - const id = html.attr('id'); - const position = html.position(); - ActionDialog._lastPosition.set(id, {top: position.top, left: position.left}); - } - - /** @inheritdoc */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - template : `modules/${MODULE.data.name}/templates/ActionDialog.html`, - classes: ["simbul-creature-aide","action-dialog"], - resizable: false, - id: ActionDialog.DEFAULT_ID, - jQuery : true, - height: "100%", - close: ActionDialog.storePosition, - popOutModuleDisable: true, - }); - } - - get title() { - return this.data.title; - } - - _generateCombatantData() { - return this.data.combatants.map((combatant) => { - return { - id : combatant.id, - combatId: combatant.combat.id, - img : combatant.img, - name : combatant.name, - items : { - action : this.options?.action ? this.getCombatantItemData(combatant, "action") : undefined, - bonus : this.options?.bonus ? this.getCombatantItemData(combatant, "bonus") : undefined, - reaction : this.options?.reaction ? this.getCombatantItemData(combatant, "reaction"): undefined, - legendary : this.options?.legendary ? this.getCombatantItemData(combatant, "legendary") : undefined, - lair : this.options?.lair ? this.getCombatantItemData(combatant, "lair") : undefined, - special : this.options?.special ? this.getCombatantItemData(combatant, "special") : undefined, - } - } - }); - - } - - getCombatantItemData(combatant, type){ - return combatant.actor.items - .filter(item => item?.system?.activation?.type === type) - .map( (item) => { - /* common data */ - let data = { - name : item.name, - id : item.id, - activation : mergeObject(getProperty(item,'system.activation'), {canUse: true}), - description : getProperty(item ,'system.description.value'), - img : item.img, - uuid : item.uuid, - } - - /* special case data -- legendary actions REQUIRE available resources */ - switch(type){ - case 'legendary': - mergeObject(data.activation, { available : getProperty(combatant.actor, 'system.resources.legact.value') } ); - data.activation.canUse = data.activation.available >= data.activation.cost; - break; - } - - return data; - }); - } - - getData(options) { - let data = super.getData(options); - data.combatants = this._generateCombatantData(); - return data; - } - - update(){ - return this.render(true); - } - - setPosition(options = {}) { - options.height = '100%' - const position = super.setPosition(options); - return position; - } - - - /* - Overwrite - */ - activateListeners(html){ - super.activateListeners(html); - - /* register img and item clicks for each combatant */ - this.data.combatants.forEach( (combatant) => { - html.find(`#${combatant.id}`).on('click', this._onImgClick); - }); - - html.find('.item').on('click', this._onButtonClick.bind(this)); - } - - - _onImgClick(event){ - logger.debug("_onImgClick | DATA | ", { event }); - const combatantID = event.currentTarget.id; - if (!combatantID || !game.combats.active) return; - - const token = game.combats.active.combatants.get(combatantID)?.token.object; - if (!token) return; - - token.control({ releaseOthers : true }); - canvas.animatePan({ x : token.x, y : token.y }); - } - - async _onButtonClick(event){ - const itemUUID = event.currentTarget.id; - const item = await fromUuid(itemUUID); - - if (!item || !(item instanceof Item)) return; - - await item.use(); - logger.debug("onButtonClick | DATA | ", { event, itemUUID, item }); - - /* close the dialog if only one combatant can do a thing here */ - if (this.data.combatants.length == 1) { - return this.close(); - } else { - return this.update(); - } - } -} diff --git a/scripts/apps/config-app.js b/scripts/apps/config-app.js index 390f9b8..ac5af28 100644 --- a/scripts/apps/config-app.js +++ b/scripts/apps/config-app.js @@ -1,5 +1,6 @@ import { MODULE } from "../module.js"; -import { logger } from "../logger.js"; +import { HELPER } from "../../../simbuls-athenaeum/scripts/helper.js"; +import { logger } from "../../../simbuls-athenaeum/scripts/logger.js"; /** * HelpersSettingConfig extends {SettingsConfig} @@ -37,9 +38,9 @@ export class HelpersSettingsConfig extends SettingsConfig { /**@override */ static get defaultOptions(){ return mergeObject(super.defaultOptions, { - title : MODULE.localize("Helpers"), + title : HELPER.localize("Helpers"), id : "creature-aide-client-settings", - template : `${MODULE.data.path}/templates/ModularSettings.html`, + template : `${MODULE.data.athenaeum}/templates/ModularSettings.html`, width : 600, height : "auto", tabs : [ @@ -88,7 +89,7 @@ export class HelpersSettingsConfig extends SettingsConfig { const canConfigure = game.user.can("SETTING_MODIFY"); const settings = Array.from(game.settings.settings); - options.title = MODULE.format('SCA.ConfigApp.title'); + options.title = HELPER.format('SCA.ConfigApp.title'); let data = { tabs: duplicate(options.groupLabels), hasParent: !!options.subMenuId, @@ -133,7 +134,7 @@ export class HelpersSettingsConfig extends SettingsConfig { isCheckbox : setting.type === Boolean, isSelect : setting.choices !== undefined, isRange : setting.type === Number && setting.range, - value : MODULE.setting(setting.key), + value : HELPER.setting(MODULE.data.name, setting.key), path: `${setting.namespace}.${setting.key}` }); } @@ -154,7 +155,7 @@ export class HelpersSettingsConfig extends SettingsConfig { return acc; }, {}) - logger.debug("GET DATA | DATA | ", data); + logger.debug(MODULE.data.name, "GET DATA | DATA | ", data); return { user : game.user, canConfigure, systemTitle : game.system.title, data diff --git a/scripts/creature-aide.js b/scripts/creature-aide.js index be892ba..5a135de 100644 --- a/scripts/creature-aide.js +++ b/scripts/creature-aide.js @@ -2,7 +2,6 @@ * Main Module Organizational Tools */ import { MODULE } from './module.js'; -import { logger } from './logger.js'; /** * Sub Modules @@ -15,7 +14,6 @@ import { UndeadFortitude } from './modules/UndeadFortitude.js'; const SUB_MODULES = { MODULE, - logger, AbilityRecharge, LegendaryActionManagement, LairActionManagement, diff --git a/scripts/logger.js b/scripts/logger.js deleted file mode 100644 index 0cbef58..0000000 --- a/scripts/logger.js +++ /dev/null @@ -1,37 +0,0 @@ -import { MODULE } from './module.js' - -export class logger { - static info(...args) { - console.log(`${MODULE?.data?.title || "" } | `, ...args); - } - - static debug(...args) { - if (MODULE.setting('debug')) { - this.info("DEBUG | ", ...args); - } - } - - static error(...args) { - console.error(`${MODULE?.data?.title || "" } | ERROR | `, ...args); - ui.notifications.error(`${MODULE?.data?.title || "" } | ERROR | ${args[0]}`); - } - - static notify(...args) { - ui.notifications.notify(`${args[0]}`); - } - - static register(){ - this.settings() - } - - static settings(){ - const config = true; - const settingsData = { - debug : { - scope: "world", config, default: false, type: Boolean, - }, - }; - - MODULE.applySettings(settingsData); - } -} diff --git a/scripts/module.js b/scripts/module.js index 48a07a1..0db05b5 100644 --- a/scripts/module.js +++ b/scripts/module.js @@ -1,6 +1,10 @@ -import { logger } from './logger.js'; +import { logger } from '../../simbuls-athenaeum/scripts/logger.js'; +import { HELPER } from '../../simbuls-athenaeum/scripts/helper.js' import { HelpersSettingsConfig } from './apps/config-app.js'; +const ATHENAEUM_NAME = `simbuls-athenaeum`; +const ATHENAEUM_PATH = `/modules/${ATHENAEUM_NAME}`; + const NAME = "simbuls-creature-aide"; const PATH = `/modules/${NAME}`; const TITLE = "Simbul's Creature Aide"; @@ -10,16 +14,17 @@ const TITLE = "Simbul's Creature Aide"; * @class * @property {Function} patch */ -export class MODULE{ +export class MODULE { static async register(){ - logger.info("Initializing Module"); + logger.info(NAME, "Initializing Module"); MODULE.globals(); MODULE.settings(); + MODULE.debugSettings(); } static async build(){ MODULE.data = { - name : NAME, path : PATH, title : TITLE + name : NAME, path : PATH, title : TITLE, athenaeum : ATHENAEUM_PATH }; } @@ -29,94 +34,34 @@ export class MODULE{ static settings() { game.settings.registerMenu(MODULE.data.name, "helperOptions", { - name : MODULE.format("setting.ConfigOption.name"), - label : MODULE.format("setting.ConfigOption.label"), + name : HELPER.format("setting.ConfigOption.name"), + label : HELPER.format("setting.ConfigOption.label"), icon : "fas fa-user-cog", type : HelpersSettingsConfig, restricted : false, }); } - /** - * @returns any - */ - static setting(key){ - return game.settings.get(MODULE.data.name, key); - } - - static localize(...args){ - return game.i18n.localize(...args); - } + static debugSettings() { + const config = true; + const settingsData = { + debug : { + scope: "world", config, default: false, type: Boolean, + }, + }; - static format(...args){ - return game.i18n.format(...args); + MODULE.applySettings(settingsData); } static applySettings(settingsData){ Object.entries(settingsData).forEach(([key, data])=> { game.settings.register( MODULE.data.name, key, { - name : MODULE.localize(`setting.${key}.name`), - hint : MODULE.localize(`setting.${key}.hint`), + name : HELPER.localize(`setting.${key}.name`), + hint : HELPER.localize(`setting.${key}.hint`), ...data } ); }); } - - static isTurnChange(combat, changed){ - /* we need a turn change or a round change to consider this a live combat */ - const liveCombat = !!combat.started && (("turn" in changed) || ('round' in changed)); - const anyCombatants = (combat.combatants.size ?? 0) !== 0; - const notFirstTurn = !(((changed.turn ?? undefined) === 0) && (changed.round ?? 0) === 1) - - return liveCombat && anyCombatants && notFirstTurn; - } - - static isFirstTurn(combat, changed){ - return combat.started && changed.round === 1; - } - - static firstGM(){ - return game.users.find(u => u.isGM && u.active); - } - - static isFirstGM(){ - return game.user.id === MODULE.firstGM()?.id; - } - - /* - * Helper function for quickly creating a simple dialog with labeled buttons and associated data. - * Useful for allowing a choice of actors to spawn prior to `warpgate.spawn`. - * - * @param `data` {Array of Objects}: Contains two keys `label` and `value`. Label corresponds to the - * button's text. Value corresponds to the return value if this button is pressed. Ex. - * `const data = buttons: [{label: 'First Choice, value: {token {name: 'First'}}, {label: 'Second Choice', - * value: {token: {name: 'Second}}}]` - * @param `direction` {String} (optional): `'column'` or `'row'` accepted. Controls layout direction of dialog. - */ - static async buttonDialog(data, direction = 'row') { - return await new Promise(async (resolve) => { - let buttons = {}, dialog; - - data.buttons.forEach((button) => { - buttons[button.label] = { - label: button.label, - callback: () => resolve(button.value) - } - }); - - dialog = new Dialog({ - title: data.title, - content: data.content, - buttons, - close: () => resolve("Exit, No Button Click") - }, { - /*width: '100%',*/ height: '100%' - }); - - await dialog._render(true); - dialog.element.find('.dialog-buttons').css({'flex-direction': direction}); - }); - } } diff --git a/scripts/modules/AbilityRecharge.js b/scripts/modules/AbilityRecharge.js index 1b4aa2e..9311bdc 100644 --- a/scripts/modules/AbilityRecharge.js +++ b/scripts/modules/AbilityRecharge.js @@ -1,12 +1,13 @@ -import { logger } from '../logger.js'; +import { logger } from '../../../simbuls-athenaeum/scripts/logger.js'; import { MODULE } from '../module.js'; -import { queueUpdate } from './update-queue.js'; +import { HELPER } from '../../../simbuls-athenaeum/scripts/helper.js'; +import { queueUpdate } from '../../../simbuls-athenaeum/scripts/update-queue.js'; const NAME = "AbilityRecharge"; export class AbilityRecharge { static register(){ - logger.info("Registering In-Combat Ability Recharge"); + logger.info(MODULE.data.name, "Registering In-Combat Ability Recharge"); AbilityRecharge.settings(); AbilityRecharge.hooks(); } @@ -17,9 +18,9 @@ export class AbilityRecharge { abilityRecharge : { scope : "world", config, group: "recharge", default: 0, type: Number, choices : { - 0 : MODULE.localize("option.arOption.Off"), - 1 : MODULE.localize("option.arOption.Start"), - 2 : MODULE.localize("option.arOption.End"), + 0 : HELPER.localize("option.arOption.Off"), + 1 : HELPER.localize("option.arOption.Start"), + 2 : HELPER.localize("option.arOption.End"), } }, hideAbilityRecharge : { @@ -36,13 +37,13 @@ export class AbilityRecharge { static _updateCombat(combat, changed) { - const setting = MODULE.setting('abilityRecharge'); + const setting = HELPER.setting(MODULE.data.name, 'abilityRecharge'); /** bail out if disabled */ if( setting == 0 ) return; /** only want the GM to operate and only on a legitimate turn change */ - if (!MODULE.isTurnChange(combat, changed) || !MODULE.isFirstGM()) return; + if (!HELPER.isTurnChange(combat, changed) || !HELPER.isFirstGM()) return; /** get the turn of interest */ const next = combat.combatants.get(combat.current.combatantId); @@ -83,7 +84,7 @@ export class AbilityRecharge { // Roll the check const roll = await(new Roll("1d6").evaluate({async: true})); const success = roll.total >= parseInt(data.recharge.value); - const rollMode = MODULE.setting("hideAbilityRecharge") == true ? "blindroll" : ""; + const rollMode = HELPER.setting(MODULE.data.name, "hideAbilityRecharge") == true ? "blindroll" : ""; // Display a Chat Message // @todo rollMode is not being respected... diff --git a/scripts/modules/LairActionManagement.js b/scripts/modules/LairActionManagement.js index 1605a7e..8b50bce 100644 --- a/scripts/modules/LairActionManagement.js +++ b/scripts/modules/LairActionManagement.js @@ -1,7 +1,8 @@ +import { logger } from '../../../simbuls-athenaeum/scripts/logger.js'; import { MODULE } from '../module.js'; -import { logger } from '../logger.js'; -import { ActionDialog } from '../apps/action-dialog.js' -import { queueUpdate } from './update-queue.js' +import { HELPER } from '../../../simbuls-athenaeum/scripts/helper.js'; +import { ActionDialog } from '../../../simbuls-athenaeum/scripts/apps/action-dialog.js' +import { queueUpdate } from '../../../simbuls-athenaeum/scripts/update-queue.js'; const NAME = "LairActionManagement"; @@ -10,7 +11,7 @@ class LairActionDialog extends ActionDialog { /** @override */ constructor(combatants) { /* Localize title */ - const title = MODULE.format("DND5E.LairActionLabel"); + const title = HELPER.format("DND5E.LairActionLabel"); /* construct an action dialog using only legendary actions */ super(combatants, {lair: true, title, id: 'lairact-action-dialog'}); @@ -55,15 +56,15 @@ export class LairActionManagement { static _createCombatant(combatant) { /* do not run if not the first GM or the feature is not enabled */ - if (!MODULE.isFirstGM() || !MODULE.setting('lairActionHelper')) return; + if (!HELPER.isFirstGM() || !HELPER.setting(MODULE.data.name, 'lairActionHelper')) return; - const usesLair = getProperty(combatant, "actor.system.resources.lair.value") - const hasLairAction = !!combatant.actor?.items.find((i) => i.system?.activation?.type === "lair") + const usesLair = getProperty(combatant, "actor.system.resources.lair.value"); + const hasLairAction = !!combatant.actor?.items.find((i) => i.system?.activation?.type === "lair"); /* flag this combatant as a lair actor for quick filtering */ - if (usesLair && hasLairAction){ - logger.debug(`${NAME} | flagging as combatant that has lair: ${combatant.name}`, combatant); - queueUpdate( async () => await combatant.setFlag(MODULE.data.name, 'hasLair', true) ) + if (usesLair && hasLairAction) { + logger.debug(MODULE.data.name, `${NAME} | flagging as combatant that has lair: ${combatant.name}`, combatant); + queueUpdate( async () => await combatant.setFlag(MODULE.data.name, 'hasLair', true) ); } } @@ -76,10 +77,10 @@ export class LairActionManagement { static _updateCombat(combat, changed) { /* do not run if not the first GM or the feature is not enabled */ - if (!MODULE.isFirstGM() || !MODULE.setting('lairActionHelper')) return; + if (!HELPER.isFirstGM() || !HELPER.setting(MODULE.data.name, 'lairActionHelper')) return; /* only trigger lair actions on a legit turn change */ - if (!MODULE.isTurnChange(combat, changed)) return; + if (!HELPER.isTurnChange(combat, changed)) return; const allLairCombatants = combat.combatants.filter( combatant => combatant.getFlag(MODULE.data.name, 'hasLair') ); @@ -93,7 +94,7 @@ export class LairActionManagement { /* check if we have wrapped around and simulate its previous initiative */ /* lair init should be inside this range or outside? */ - const inside = previousInit - currentInit > 0; + const inside = previousInit - currentInit >= 0; const containsLair = (combatant) => { const init = combatant.actor.system.resources.lair.initiative diff --git a/scripts/modules/LegendaryActionManagement.js b/scripts/modules/LegendaryActionManagement.js index 353aaa4..e3e84d2 100644 --- a/scripts/modules/LegendaryActionManagement.js +++ b/scripts/modules/LegendaryActionManagement.js @@ -1,7 +1,8 @@ +import { logger } from '../../../simbuls-athenaeum/scripts/logger.js'; import { MODULE } from '../module.js'; -import { logger } from '../logger.js'; -import { ActionDialog } from '../apps/action-dialog.js' -import { queueUpdate } from './update-queue.js' +import { HELPER } from '../../../simbuls-athenaeum/scripts/helper.js'; +import { ActionDialog } from '../../../simbuls-athenaeum/scripts/apps/action-dialog.js' +import { queueUpdate } from '../../../simbuls-athenaeum/scripts/update-queue.js'; const NAME = "LegendaryActionManagement"; @@ -12,7 +13,7 @@ class LegendaryActionDialog extends ActionDialog { constructor(combatants) { /* Localize title */ - const title = MODULE.format("DND5E.LegAct"); + const title = HELPER.format("DND5E.LegAct"); /* construct an action dialog using only legendary actions */ super(combatants, {legendary: true, title, id:'legact-action-dialog'}); @@ -61,13 +62,13 @@ export class LegendaryActionManagement { */ static _createCombatant(combatant) { /* do not run if not the first GM, but always flag regardless of enable state */ - if (!MODULE.isFirstGM()) return; + if (!HELPER.isFirstGM()) return; const hasLegendary = !!combatant.actor?.items.find((i) => i.system?.activation?.type === "legendary") /* flag this combatant as a legendary actor for quick filtering */ if (hasLegendary) { - logger.debug(`${NAME} | flagging as legendary combatant: ${combatant.name}`, combatant); + logger.debug(MODULE.data.name, `${NAME} | flagging as legendary combatant: ${combatant.name}`, combatant); queueUpdate( async () => await combatant.setFlag(MODULE.data.name, 'hasLegendary', true) ) } } @@ -80,15 +81,15 @@ export class LegendaryActionManagement { */ static _updateCombat(combat, changed) { /* do not run if not the first GM or the feature is not enabled */ - if (!MODULE.isFirstGM()) return; + if (!HELPER.isFirstGM()) return; /* only trigger legendary actions on a legit turn change */ - if (!MODULE.isTurnChange(combat, changed)) return; + if (!HELPER.isTurnChange(combat, changed)) return; const previousId = combat.previous?.combatantId; /* run the leg action helper dialog if enabled */ - if (MODULE.setting('legendaryActionHelper')) { + if (HELPER.setting(MODULE.data.name, 'legendaryActionHelper')) { /* Collect legendary combatants (but not the combatant whose turn just ended) */ let legendaryCombatants = combat.combatants.filter( combatant => combatant.getFlag(MODULE.data.name, 'hasLegendary') && combatant.id != previousId ); @@ -103,7 +104,7 @@ export class LegendaryActionManagement { } /* recharge the legendary actions, if enabled */ - if (MODULE.setting('legendaryActionRecharge')) { + if (HELPER.setting(MODULE.data.name, 'legendaryActionRecharge')) { /* once the dialog for the "in-between" turn has been rendered, recharge legendary actions * for the creature whose turn just ended. This is not entirely RAW, but due to order diff --git a/scripts/modules/Regeneration.js b/scripts/modules/Regeneration.js index ee69a77..14d6023 100644 --- a/scripts/modules/Regeneration.js +++ b/scripts/modules/Regeneration.js @@ -1,13 +1,14 @@ -import { logger } from '../logger.js'; +import { logger } from '../../../simbuls-athenaeum/scripts/logger.js'; import { MODULE } from '../module.js'; -import { queueUpdate } from './update-queue.js'; +import { HELPER } from '../../../simbuls-athenaeum/scripts/helper.js'; +import { queueUpdate } from '../../../simbuls-athenaeum/scripts/update-queue.js'; const NAME = "Regeneration"; export class Regeneration { static register() { - logger.info("Registering Automatic Regeneration"); + logger.info(MODULE.data.name, "Registering Automatic Regeneration"); Regeneration.settings(); Regeneration.hooks(); } @@ -19,7 +20,7 @@ export class Regeneration { scope : "world", config, group: "regen", default: 0, type: Boolean, }, regenBlock : { - scope : "world", config, group: "regen", default: MODULE.localize('SCA.regenBlock_default'), type: String, + scope : "world", config, group: "regen", default: HELPER.localize('SCA.regenBlock_default'), type: String, } }; @@ -33,20 +34,20 @@ export class Regeneration { static _updateCombat(combat, changed) { - const setting = MODULE.setting('autoRegen'); + const setting = HELPER.setting(MODULE.data.name, 'autoRegen'); /** bail out if disabled */ if( setting == 0 ) return; /** only want the GM to operate and only on a legitimate turn change */ - if (!MODULE.isTurnChange(combat, changed) || !MODULE.isFirstGM()) return; + if (!HELPER.isTurnChange(combat, changed) || !HELPER.isFirstGM()) return; /** get the actor whose turn it just changed to */ const next = combat.combatants.get(combat.current.combatantId); const token = next.token?.object; if(!token) { - logger.debug('Could not find a valid token in the upcoming turn.'); + logger.debug(MODULE.data.name, 'Could not find a valid token in the upcoming turn.'); return; } @@ -64,17 +65,17 @@ export class Regeneration { static _getRegenFeature(actor) { if(!actor) { - logger.debug('Cannot regenerate a null actor'); + logger.debug(MODULE.data.name, 'Cannot regenerate a null actor'); return null; } /** before we check anything else, is regen blocked on this actor? */ - const regenBlockName = MODULE.setting("regenBlock"); + const regenBlockName = HELPER.setting(MODULE.data.name, "regenBlock"); const blockEffect = actor.effects?.find(e => e.label === regenBlockName ); const enabledBlockEffect = !(getProperty(blockEffect ?? {}, 'disabled') ?? true); if (enabledBlockEffect) { - logger.debug(`${actor.name}'s regeneration blocked by ${blockEffect.label}`); + logger.debug(MODULE.data.name, `${actor.name}'s regeneration blocked by ${blockEffect.label}`); return null; } @@ -97,12 +98,12 @@ export class Regeneration { static _parseRegenFeature(item) { /* @todo localize 'hit points'! */ - const hitPointsString = MODULE.localize("SCA.AutoRegen_HP"); + const hitPointsString = HELPER.localize("SCA.AutoRegen_HP"); const regenRegExp = new RegExp(`([0-9]+|[0-9]*d0*[1-9][0-9]*) ${hitPointsString}`); let match = item.system.description.value.match(regenRegExp); if (!match) { - logger.debug(`Could not parse ${item.name}'s description for a regeneration value containing ${hitPointsString}`); + logger.debug(MODULE.data.name, `Could not parse ${item.name}'s description for a regeneration value containing ${hitPointsString}`); return null; } diff --git a/scripts/modules/UndeadFortitude.js b/scripts/modules/UndeadFortitude.js index 33b4718..bfa81fd 100644 --- a/scripts/modules/UndeadFortitude.js +++ b/scripts/modules/UndeadFortitude.js @@ -1,13 +1,14 @@ -import { logger } from '../logger.js'; +import { logger } from '../../../simbuls-athenaeum/scripts/logger.js'; import { MODULE } from '../module.js'; -import { queueUpdate } from './update-queue.js'; +import { HELPER } from '../../../simbuls-athenaeum/scripts/helper.js'; +import { queueUpdate } from '../../../simbuls-athenaeum/scripts/update-queue.js'; const NAME = "UndeadFortitude"; export class UndeadFortitude { static register() { - logger.info("Registering Undead Fortitude"); + logger.info(MODULE.data.name, "Registering Undead Fortitude"); UndeadFortitude.settings(); UndeadFortitude.defaults(); UndeadFortitude.hooks(); @@ -38,8 +39,8 @@ export class UndeadFortitude { MODULE.applySettings(settingsData); CONFIG.DND5E.characterFlags.helpersUndeadFortitude = { - hint: MODULE.localize("SCA.flagsUndeadFortitudeHint"), - name: MODULE.localize("SCA.flagsUndeadFortitude"), + hint: HELPER.localize("SCA.flagsUndeadFortitudeHint"), + name: HELPER.localize("SCA.flagsUndeadFortitude"), section: "Feats", default:false, type: Boolean @@ -63,13 +64,13 @@ export class UndeadFortitude { static _preUpdateActor(actor, update, options/*, userId*/) { /* bail if not enabled */ - if (!(MODULE.setting('undeadFortEnable') > 0)) return; + if (!(HELPER.setting(MODULE.data.name, 'undeadFortEnable') > 0)) return; /* bail if HP isnt being modified */ if ( getProperty(update, "system.attributes.hp.value") == undefined ) return; /* Bail if the actor does not have undead fortitude and the flag is not set to true (shakes fist at double negatives)*/ - if (!actor.items.getName(MODULE.setting("undeadFortName")) && !actor.getFlag("dnd5e","helpersUndeadFortitude")) return; + if (!actor.items.getName(HELPER.setting(MODULE.data.name, "undeadFortName")) && !actor.getFlag("dnd5e","helpersUndeadFortitude")) return; /* collect the needed information and pass it along to the handler */ const originalHp = actor.system.attributes.hp.value; @@ -80,12 +81,12 @@ export class UndeadFortitude { actor, finalHp, hpDelta, - ignoredDamageTypes: MODULE.setting('undeadFortDamageTypes'), - baseDc: MODULE.setting('undeadFortDC'), + ignoredDamageTypes: HELPER.setting(MODULE.data.name, 'undeadFortDamageTypes'), + baseDc: HELPER.setting(MODULE.data.name, 'undeadFortDC'), skipCheck: options.skipUndeadCheck, }; - logger.debug(`${NAME} data`, data); + logger.debug(MODULE.data.name, `${NAME} data`, data); UndeadFortitude.runSave(data, options); } @@ -98,17 +99,17 @@ export class UndeadFortitude { /* we have been requested to run the save, check threshold DC */ if (data.finalHp > MODULE[NAME].hpThreshold) { - logger.debug(`${NAME} | Actor has feat, but hasnt hit the threshold`); + logger.debug(MODULE.data.name, `${NAME} | Actor has feat, but hasnt hit the threshold`); return; } if (options.skipUndeadCheck){ - logger.debug(`${NAME} | Skipped undead fortitude check via options`); + logger.debug(MODULE.data.name, `${NAME} | Skipped undead fortitude check via options`); return; } /* get the DC */ - const mode = MODULE.setting('undeadFortEnable') + const mode = HELPER.setting(MODULE.data.name, 'undeadFortEnable') queueUpdate( async () => { const saveInfo = await UndeadFortitude._getUndeadFortSave(data, mode === 2 ? true : false ); @@ -122,15 +123,15 @@ export class UndeadFortitude { if (saveInfo.rollSave) { /* but roll the save if we need to and check */ - const result = (await data.actor.rollAbilitySave('con', {flavor: `${MODULE.setting('undeadFortName')} - DC ${saveInfo.saveDc}`, rollMode: 'gmroll'})).total; + const result = (await data.actor.rollAbilitySave('con', {flavor: `${HELPER.setting(MODULE.data.name, 'undeadFortName')} - DC ${saveInfo.saveDc}`, rollMode: 'gmroll'})).total; /* check for unexpected roll outputs (like BetterRolls) and simply output information * note: result == null _should_ account for result === undefined as well. */ if (result == null) { - logger.debug(`${NAME} | Could not parse result of constitution save. Echoing needed DC instead.`); + logger.debug(MODULE.data.name, `${NAME} | Could not parse result of constitution save. Echoing needed DC instead.`); - content = MODULE.format('SCA.UndeadFort_failsafe', {tokenName: messageName, dc: saveInfo.saveDc}); + content = HELPER.format('SCA.UndeadFort_failsafe', {tokenName: messageName, dc: saveInfo.saveDc}); } else { /* Otherwise, the roll result we got was valid and usable, so do the calculations ourselves */ @@ -138,16 +139,16 @@ export class UndeadFortitude { if (hasSaved) { /* they saved, report and restore to 1 HP */ - content = MODULE.format("SCA.UndeadFort_surivalmessage", { tokenName: messageName, total: result }); + content = HELPER.format("SCA.UndeadFort_surivalmessage", { tokenName: messageName, total: result }); await data.actor.update({'data.attributes.hp.value': 1}); } else { /* rolled and failed, but not instantly via damage type */ - content = MODULE.format("SCA.UndeadFort_deathmessage", { tokenName: messageName, total: result }); + content = HELPER.format("SCA.UndeadFort_deathmessage", { tokenName: messageName, total: result }); } } } else { /* this is an auto-fail due to damage type, do not update remain at 0 */ - content = MODULE.format("SCA.UndeadFort_insantdeathmessage", { tokenName: messageName}); + content = HELPER.format("SCA.UndeadFort_insantdeathmessage", { tokenName: messageName}); } await ChatMessage.create({content, speaker, whisper }); @@ -165,20 +166,20 @@ export class UndeadFortitude { saveInfo = await UndeadFortitude.quickCheck(data); } - logger.debug(`${NAME} undead fort. info:`, saveInfo); + logger.debug(MODULE.data.name, `${NAME} undead fort. info:`, saveInfo); return saveInfo; } static quickCheck(data) { - return MODULE.buttonDialog({ - title: MODULE.localize("SCA.UndeadFort_dialogname"), - content: MODULE.localize("SCA.UndeadFort_quickdialogcontent"), + return HELPER.buttonDialog({ + title: HELPER.localize("SCA.UndeadFort_dialogname"), + content: HELPER.localize("SCA.UndeadFort_quickdialogcontent"), buttons: [{ - label: MODULE.format("SCA.UndeadFort_quickdialogprompt1", { types: data.ignoredDamageTypes }), + label: HELPER.format("SCA.UndeadFort_quickdialogprompt1", { types: data.ignoredDamageTypes }), value: { rollSave: false, saveDc: 0 } }, { - label: MODULE.localize("SCA.UndeadFort_quickdialogprompt2"), + label: HELPER.localize("SCA.UndeadFort_quickdialogprompt2"), value: { rollSave: true, saveDc: data.baseDc + data.hpDelta }, }], }); @@ -188,7 +189,7 @@ export class UndeadFortitude { const ignoredDamageTypes = data.ignoredDamageTypes; if (data.skipUndeadCheck) return; - let damageQuery = MODULE.format("SCA.UndeadFort_slowdialogcontentquery") + let damageQuery = HELPER.format("SCA.UndeadFort_slowdialogcontentquery") let content = `