diff --git a/module/actor-sheet.js b/module/actor-sheet.js index dc7a9ca..91696bd 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -24,11 +24,7 @@ export class SimpleActorSheet extends ActorSheet { /** @override */ getData() { const data = super.getData(); - - // Handle attribute groups. EntitySheetHelper.getAttributeData(data); - - // Add shorthand. data.shorthand = !!game.settings.get("worldbuilding", "macroShorthand"); return data; } @@ -39,15 +35,13 @@ export class SimpleActorSheet extends ActorSheet { activateListeners(html) { super.activateListeners(html); - // Handle rollable items. - html.find(".items .rollable").on("click", this._onItemRoll.bind(this)); - - // Handle rollable attributes. - html.find(".attributes").on("click", "a.attribute-roll", EntitySheetHelper.onAttributeRoll.bind(this)); - // Everything below here is only needed if the sheet is editable if ( !this.options.editable ) return; + // Handle rollable items and attributes + html.find(".items .rollable").on("click", this._onItemRoll.bind(this)); + html.find(".attributes").on("click", "a.attribute-roll", EntitySheetHelper.onAttributeRoll.bind(this)); + // Update Inventory Item html.find('.item-edit').click(ev => { const li = $(ev.currentTarget).parents(".item"); @@ -80,36 +74,6 @@ export class SimpleActorSheet extends ActorSheet { /* -------------------------------------------- */ - /** @override */ - async _onSubmit(event, {updateData=null, preventClose=false, preventRender=false}={}) { - let attr = EntitySheetHelper.onSubmit(event); - - // Submit the form if attr is true or an attr key. - if ( attr ) { - await super._onSubmit(event, {updateData: updateData, preventClose: preventClose, preventRender: preventRender}); - - // If attr is a key and not just true, set a very short timeout and retrigger focus after the original element is deleted and the new one is inserted. - if ( attr !== true) { - setTimeout(() => { - $(`input[name="${attr}"]`).parents('.attribute').find('.attribute-value').focus(); - }, 10); - } - } - } - - /* -------------------------------------------- */ - - /** @override */ - setPosition(options={}) { - const position = super.setPosition(options); - const sheetBody = this.element.find(".sheet-body"); - const bodyHeight = position.height - 192; - sheetBody.css("height", bodyHeight); - return position; - } - - /* -------------------------------------------- */ - /** * Listen for roll buttons on items. * @param {MouseEvent} event The originating left click event @@ -126,14 +90,12 @@ export class SimpleActorSheet extends ActorSheet { }); } + /* -------------------------------------------- */ + /** @override */ _updateObject(event, formData) { - - // Handle attribute and group updates. formData = EntitySheetHelper.updateAttributes(formData, this); formData = EntitySheetHelper.updateGroups(formData, this); - - // Update the Actor with the new form values. return this.object.update(formData); } diff --git a/module/helper.js b/module/helper.js index d06504e..689b279 100644 --- a/module/helper.js +++ b/module/helper.js @@ -181,7 +181,7 @@ export class EntitySheetHelper { const label = button.closest(".attribute").querySelector(".attribute-label")?.value; const chatLabel = label ?? button.parentElement.querySelector(".attribute-key").value; const shorthand = game.settings.get("worldbuilding", "macroShorthand"); - const rollData = this.actor.getRollData(); + const rollData = this.object.getRollData(); let formula = button.closest(".attribute").querySelector(".attribute-value")?.value; // If there's a formula, attempt to roll it. @@ -527,18 +527,14 @@ export class EntitySheetHelper { if ( typeof formula != "string" || depth < 1) { return 0; } - // Replace attributes with their numeric equivalents. let dataRgx = new RegExp(/@([a-z.0-9_\-]+)/gi); let rollFormula = formula.replace(dataRgx, (match, term) => { - // Replace matches with the value, or the missing value. let value = getProperty(data, term); - value = value ? String(value).trim() : (missing != null ? missing : `@${term}`); - // If there's still an attribute in the returned string, nest it in parentheses so that it's evaluated first in the roll. - value = value && value.includes('@') ? `(${value})` : value; - return value; + if ( value === null ) return "0"; + if ( String(value).includes('@') ) return value; + else return `@${term}`; }); - return rollFormula; } diff --git a/module/item-sheet.js b/module/item-sheet.js index 248cd2c..9d4a83c 100644 --- a/module/item-sheet.js +++ b/module/item-sheet.js @@ -23,55 +23,22 @@ export class SimpleItemSheet extends ItemSheet { /** @override */ getData() { const data = super.getData(); - - // Handle attribute groups. EntitySheetHelper.getAttributeData(data); - return data; } /* -------------------------------------------- */ - /** @override */ - async _onSubmit(event, {updateData=null, preventClose=false, preventRender=false}={}) { - let attr = EntitySheetHelper.onSubmit(event); - - // Submit the form if attr is true or an attr key. - if ( attr ) { - await super._onSubmit(event, {updateData: updateData, preventClose: preventClose, preventRender: preventRender}); - - // If attr is a key and not just true, set a very short timeout and retrigger focus after the original element is deleted and the new one is inserted. - if ( attr !== true) { - setTimeout(() => { - $(`input[name="${attr}"]`).parents('.attribute').find('.attribute-value').focus(); - }, 10); - } - } - } - - /* -------------------------------------------- */ - - /** @override */ - setPosition(options={}) { - const position = super.setPosition(options); - const sheetBody = this.element.find(".sheet-body"); - const bodyHeight = position.height - 192; - sheetBody.css("height", bodyHeight); - return position; - } - - /* -------------------------------------------- */ - /** @override */ activateListeners(html) { super.activateListeners(html); - // Handle rollable attributes. - html.find(".attributes").on("click", "a.attribute-roll", EntitySheetHelper.onAttributeRoll.bind(this)); - // Everything below here is only needed if the sheet is editable if (!this.options.editable) return; + // Rollable attributes + html.find(".attributes").on("click", "a.attribute-roll", EntitySheetHelper.onAttributeRoll.bind(this)); + // Add draggable for macros. html.find(".attributes a.attribute-roll").each((i, a) => { a.setAttribute("draggable", true); diff --git a/module/simple.js b/module/simple.js index 78db88b..e87ca6b 100644 --- a/module/simple.js +++ b/module/simple.js @@ -176,110 +176,66 @@ Hooks.on("getItemDirectoryEntryContext", (html, options) => { }); -/** - * Adds the actor template selection dialog. - */ -ActorDirectory.prototype._onCreateEntity = async (event) => { - // Do not allow the creation event to bubble to other listeners +async function _onCreateEntity(event) { event.preventDefault(); event.stopPropagation(); - - _simpleDirectoryTemplates('actor', event); -} - -/** - * Adds the item template selection dialog. - */ -ItemDirectory.prototype._onCreateEntity = async (event) => { - // Do not allow the creation event to bubble to other listeners - event.preventDefault(); - event.stopPropagation(); - - _simpleDirectoryTemplates('item', event); + return _simpleDirectoryTemplates(this, event); } +ActorDirectory.prototype._onCreateEntity = _onCreateEntity; // For 0.7.x+ +ItemDirectory.prototype._onCreateEntity = _onCreateEntity; +ActorDirectory.prototype._onCreate = _onCreateEntity; // TODO: for 0.6.6 +ItemDirectory.prototype._onCreate = _onCreateEntity; /** * Display the entity template dialog. * - * Helper function to display a dialog if there are multiple template types - * defined for the entity type. - * - * @param {string} entityType - 'actor' or 'item' + * Helper function to display a dialog if there are multiple template types defined for the entity type. + * TODO: Refactor in 0.7.x to play more nicely with the Entity.createDialog method + *1 + * @param {EntityCollection} entityType - The sidebar tab * @param {MouseEvent} event - Triggering event */ -async function _simpleDirectoryTemplates(entityType = 'actor', event) { - // Retrieve the collection and class. - const entityCollection = entityType == 'actor' ? game.actors : game.items; - const cls = entityType == 'actor' ? Actor : Item; +async function _simpleDirectoryTemplates(collection, event) { - // Query for all entities of this type using the "isTemplate" flag. - let entities = entityCollection.filter(a => a.data.flags?.worldbuilding?.isTemplate === true); - - // Initialize variables related to the entity class. + // Retrieve the collection and find any available templates + const entityCollection = collection.tabName === "actors" ? game.actors : game.items; + const cls = collection.tabName === "actors" ? Actor : Item; + let templates = entityCollection.filter(a => a.getFlag("worldbuilding", "isTemplate")); let ent = game.i18n.localize(cls.config.label); - // Setup entity data. - let type = entityType == 'actor' ? 'character' : 'item'; + // Setup default creation data + let type = collection.tabName === "actors" ? 'character' : 'item'; let createData = { name: `${game.i18n.localize("SIMPLE.New")} ${ent}`, type: type, folder: event.currentTarget.dataset.folder }; + if ( !templates.length ) return cls.create(createData, {renderSheet: true}); - // If there's more than one entity template type, create a form. - if (entities.length > 0) { - // Build an array of types for the form, including an empty default. - let types = [{ - value: null, - label: game.i18n.localize("SIMPLE.NoTemplate") - }]; + // Build an array of types for the form, including an empty default. + let types = [{ + value: null, + label: game.i18n.localize("SIMPLE.NoTemplate") + }].concat(templates.map(a => { return { value: a.id, label: a.name } })); - // Append each of the user-defined actor/item types. - types = types.concat(entities.map(a => { - return { - value: a.data.name, - label: a.data.name + // Render the confirmation dialog window + const templateData = {upper: ent, lower: ent.toLowerCase(), types: types}; + const dlg = await renderTemplate(`systems/worldbuilding/templates/sidebar/entity-create.html`, templateData); + return Dialog.confirm({ + title: `${game.i18n.localize("SIMPLE.Create")} ${createData.name}`, + content: dlg, + yes: html => { + const form = html[0].querySelector("form"); + const template = entityCollection.get(form.type.value); + if ( template ) { + createData = mergeObject(template.data, createData, {inplace: false}); + createData.type = template.data.type; + delete createData.flags.worldbuilding.isTemplate; } - })); - - // Render the entity creation form - let templateData = {upper: ent, lower: ent.toLowerCase(), types: types}, - dlg = await renderTemplate(`systems/worldbuilding/templates/sidebar/entity-create.html`, templateData); - - // Render the confirmation dialog window - Dialog.confirm({ - title: `${game.i18n.localize("SIMPLE.Create")} ${createData.name}`, - content: dlg, - yes: html => { - // Get the form data. - const form = html[0].querySelector("form"); - const fd = new FormDataExtended(form); - mergeObject(createData, fd.toObject()); - - // Store the type and name values, and retrieve the template entity. - let templateActor = entityCollection.getName(createData.type); - - // If there's a template entity, handle the data. - if (templateActor) { - // Update the object with the existing template's values. - createData = mergeObject(templateActor.data, createData, {inplace: false}); - createData.type = templateActor.data.type; - // Clear the flag so that this doesn't become a new template. - delete createData.flags.worldbuilding.isTemplate; - } - // Otherwise, restore to a valid entity type (character/item). - else { - createData.type = type; - } - - cls.create(createData, {renderSheet: true}); - }, - no: () => {}, - defaultYes: false - }); - } - // Otherwise, just create a blank entity. - else { - cls.create(createData, {renderSheet: true}); - } + createData.name = form.name.value; + return cls.create(createData, {renderSheet: true}); + }, + no: () => {}, + defaultYes: false + }); } \ No newline at end of file diff --git a/styles/simple.css b/styles/simple.css index 7c37aac..09e8e4f 100644 --- a/styles/simple.css +++ b/styles/simple.css @@ -8,8 +8,11 @@ padding: 5px; overflow-y: hidden; } +.worldbuilding form { + height: 100%; +} .worldbuilding .sheet-header { - height: 100px; + flex: 0 0 100px; overflow: hidden; display: flex; flex-direction: row; @@ -49,7 +52,7 @@ height: 28px; } .worldbuilding .tabs { - height: 40px; + flex: 0 0 40px; border-top: 1px solid #AAA; border-bottom: 1px solid #AAA; } diff --git a/styles/simple.less b/styles/simple.less index c489d23..e5e2267 100644 --- a/styles/simple.less +++ b/styles/simple.less @@ -5,8 +5,12 @@ overflow-y: hidden; } + form { + height: 100%; + } + .sheet-header { - height: 100px; + flex: 0 0 100px; overflow: hidden; display: flex; flex-direction: row; @@ -52,7 +56,7 @@ /* Sheet Tabs */ .tabs { - height: 40px; + flex: 0 0 40px; border-top: 1px solid #AAA; border-bottom: 1px solid #AAA; diff --git a/system.json b/system.json index ea7d160..1ba9387 100644 --- a/system.json +++ b/system.json @@ -1,9 +1,9 @@ { "name": "worldbuilding", "title": "Simple World-Building", - "description": "A minimalist game system with very simple Actor and Item models to support free-form system agnostic gameplay.", - "version": 0.36, - "minimumCoreVersion": "0.7.3", + "description": "A minimalist game system which provides configurable Actor and Item templates to support free-form system agnostic game-play.", + "version": 0.40, + "minimumCoreVersion": "0.6.6", "compatibleCoreVersion": "0.7.3", "templateVersion": 2, "author": "Atropos", @@ -23,6 +23,6 @@ "secondaryTokenAttribute": "power", "url": "https://gitlab.com/foundrynet/worldbuilding/", "manifest": "https://gitlab.com/foundrynet/worldbuilding/raw/master/system.json", - "download": "https://gitlab.com/foundrynet/worldbuilding/-/archive/release-036/worldbuilding-release-036.zip", + "download": "https://gitlab.com/foundrynet/worldbuilding/-/archive/release-040/worldbuilding-release-040.zip", "license": "LICENSE.txt" } diff --git a/templates/actor-sheet.html b/templates/actor-sheet.html index bac456b..d0795d1 100644 --- a/templates/actor-sheet.html +++ b/templates/actor-sheet.html @@ -1,4 +1,4 @@ -