diff --git a/module/actor.js b/module/actor.js index 8288404..acaee33 100644 --- a/module/actor.js +++ b/module/actor.js @@ -11,6 +11,7 @@ export class SimpleActor extends Actor { super.prepareDerivedData(); this.data.data.groups = this.data.data.groups || {}; this.data.data.attributes = this.data.data.attributes || {}; + EntitySheetHelper.clampResourceValues(this.data.data.attributes); } /* -------------------------------------------- */ @@ -236,4 +237,17 @@ export class SimpleActor extends Actor { } } } + + /* -------------------------------------------- */ + + /** @inheritdoc */ + async modifyTokenAttribute(attribute, value, isDelta = false, isBar = true) { + const current = foundry.utils.getProperty(this.data.data, attribute); + if ( !isBar || !isDelta || (current?.dtype !== "Resource") ) { + return super.modifyTokenAttribute(attribute, value, isDelta, isBar); + } + const updates = {[`data.${attribute}.value`]: Math.clamped(current.value + value, current.min, current.max)}; + const allowed = Hooks.call("modifyTokenAttribute", {attribute, value, isDelta, isBar}, updates); + return allowed !== false ? this.update(updates) : this; + } } diff --git a/module/helper.js b/module/helper.js index 4997798..dd04769 100644 --- a/module/helper.js +++ b/module/helper.js @@ -587,4 +587,21 @@ export class EntitySheetHelper { options: options }); } + + /* -------------------------------------------- */ + + /** + * Ensure the resource values are within the specified min and max. + * @param {object} attrs The Document's attributes. + */ + static clampResourceValues(attrs) { + const flat = foundry.utils.flattenObject(attrs); + for ( const [attr, value] of Object.entries(flat) ) { + const parts = attr.split("."); + if ( parts.pop() !== "value" ) continue; + const current = foundry.utils.getProperty(attrs, parts.join(".")); + if ( current?.dtype !== "Resource" ) continue; + foundry.utils.setProperty(attrs, attr, Math.clamped(value, current.min || 0, current.max || 0)); + } + } } diff --git a/module/item.js b/module/item.js index b4e0cce..5cfb6a8 100644 --- a/module/item.js +++ b/module/item.js @@ -11,6 +11,7 @@ export class SimpleItem extends Item { super.prepareDerivedData(); this.data.data.groups = this.data.data.groups || {}; this.data.data.attributes = this.data.data.attributes || {}; + EntitySheetHelper.clampResourceValues(this.data.data.attributes); } /* -------------------------------------------- */ diff --git a/module/simple.js b/module/simple.js index 059bea6..59b663c 100644 --- a/module/simple.js +++ b/module/simple.js @@ -10,7 +10,7 @@ import { SimpleItemSheet } from "./item-sheet.js"; import { SimpleActorSheet } from "./actor-sheet.js"; import { preloadHandlebarsTemplates } from "./templates.js"; import { createWorldbuildingMacro } from "./macro.js"; -import { SimpleTokenDocument } from "./simpletokendocument.js"; +import { SimpleToken, SimpleTokenDocument } from "./token.js"; /* -------------------------------------------- */ /* Foundry VTT Initialization */ @@ -40,9 +40,8 @@ Hooks.once("init", async function() { // Define custom Document classes CONFIG.Actor.documentClass = SimpleActor; CONFIG.Item.documentClass = SimpleItem; - - // Update TokenDocument with overrided getBarAttribute method CONFIG.Token.documentClass = SimpleTokenDocument; + CONFIG.Token.objectClass = SimpleToken; // Register sheet application classes Actors.unregisterSheet("core", ActorSheet); diff --git a/module/token.js b/module/token.js new file mode 100644 index 0000000..220826b --- /dev/null +++ b/module/token.js @@ -0,0 +1,38 @@ +/** + * Extend the base TokenDocument to allow resource to support resource type attributes. + * @extends {TokenDocument} + */ +export class SimpleTokenDocument extends TokenDocument { + /** @inheritdoc */ + getBarAttribute(barName, {alternative}={}) { + const data = super.getBarAttribute(barName, {alternative}); + const attr = alternative || this.data[barName]?.attribute; + if ( !data || !attr || !this.actor ) return data; + const current = foundry.utils.getProperty(this.actor.data.data, attr); + if ( "min" in current ) data.min = parseInt(current.min || 0); + data.editable = true; + return data; + } +} + + +/* -------------------------------------------- */ + + +/** + * Extend the base Token class to implement additional system-specific logic. + * @extends {Token} + */ +export class SimpleToken extends Token { + _drawBar(number, bar, data) { + if ( "min" in data ) { + // Copy the data to avoid mutating what the caller gave us. + data = {...data}; + // Shift the value and max by the min to ensure that the bar's percentage is drawn accurately if this resource has + // a non-zero min. + data.value -= data.min; + data.max -= data.min; + } + return super._drawBar(number, bar, data); + } +}