diff --git a/module/actor-sheet.js b/module/actor-sheet.js index 7f88617..2817ad2 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -33,14 +33,6 @@ export class SimpleActorSheet extends ActorSheet { activateListeners(html) { super.activateListeners(html); - // Activate tabs - let tabs = html.find('.tabs'); - let initial = this._sheetTab; - new Tabs(tabs, { - initial: initial, - callback: clicked => this._sheetTab = clicked.data("tab") - }); - // Everything below here is only needed if the sheet is editable if (!this.options.editable) return; @@ -64,6 +56,17 @@ export class SimpleActorSheet extends ActorSheet { /* -------------------------------------------- */ + /** @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 click events on an attribute control to modify the composition of attributes in the sheet * @param {MouseEvent} event The originating left click event diff --git a/module/actor.js b/module/actor.js new file mode 100644 index 0000000..0f85c7f --- /dev/null +++ b/module/actor.js @@ -0,0 +1,35 @@ +/** + * Extend the base Actor entity by defining a custom roll data structure which is ideal for the Simple system. + * @extends {Actor} + */ +export class SimpleActor extends Actor { + + /** @override */ + getRollData() { + const data = super.getRollData(); + const shorthand = game.settings.get("worldbuilding", "macroShorthand"); + + // Re-map all attributes onto the base roll data + if ( !!shorthand ) { + for ( let [k, v] of Object.entries(data.attributes) ) { + if ( !(k in data) ) data[k] = v.value; + } + delete data.attributes; + } + + // Map all items data using their slugified names + data.items = this.data.items.reduce((obj, i) => { + let key = i.name.slugify({strict: true}); + let itemData = duplicate(i.data); + if ( !!shorthand ) { + for ( let [k, v] of Object.entries(itemData.attributes) ) { + if ( !(k in itemData) ) itemData[k] = v.value; + } + delete itemData["attributes"]; + } + obj[key] = itemData; + return obj; + }, {}); + return data; + } +} diff --git a/module/item-sheet.js b/module/item-sheet.js index eb3918b..8d378e1 100644 --- a/module/item-sheet.js +++ b/module/item-sheet.js @@ -29,18 +29,21 @@ export class SimpleItemSheet extends ItemSheet { /* -------------------------------------------- */ + /** @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); - // Activate tabs - let tabs = html.find('.tabs'); - let initial = this._sheetTab; - new Tabs(tabs, { - initial: initial, - callback: clicked => this._sheetTab = clicked.data("tab") - }); - // Everything below here is only needed if the sheet is editable if (!this.options.editable) return; diff --git a/module/simple.js b/module/simple.js index 75da997..a2337ac 100644 --- a/module/simple.js +++ b/module/simple.js @@ -5,6 +5,7 @@ */ // Import Modules +import { SimpleActor } from "./actor.js"; import { SimpleItemSheet } from "./item-sheet.js"; import { SimpleActorSheet } from "./actor-sheet.js"; @@ -24,9 +25,22 @@ Hooks.once("init", async function() { decimals: 2 }; + // Define custom Entity classes + CONFIG.Actor.entityClass = SimpleActor; + // Register sheet application classes Actors.unregisterSheet("core", ActorSheet); Actors.registerSheet("dnd5e", SimpleActorSheet, { makeDefault: true }); Items.unregisterSheet("core", ItemSheet); Items.registerSheet("dnd5e", SimpleItemSheet, {makeDefault: true}); + + // Register system settings + game.settings.register("worldbuilding", "macroShorthand", { + name: "Shortened Macro Syntax", + hint: "Enable a shortened macro syntax which allows referencing attributes directly, for example @str instead of @attributes.str.value. Disable this setting if you need the ability to reference the full attribute model, for example @attributes.str.label.", + scope: "world", + type: Boolean, + default: true, + config: true + }); }); diff --git a/styles/simple.css b/styles/simple.css index a2c0aba..0fe998f 100644 --- a/styles/simple.css +++ b/styles/simple.css @@ -1,144 +1,139 @@ -.worldbuilding.sheet .window-content { - padding: 5px; - overflow-y: hidden; +.worldbuilding { + /* Sheet Tabs */ + /* Items List */ + /* Attributes */ } - -/* Sheet Header */ -.worldbuilding.sheet .sheet-header { - overflow: hidden; - display: flex; - flex-direction: row; - flex-wrap: wrap; - justify-content: flex-start; - flex: 0 0 100px; - margin-bottom: 10px; +.worldbuilding .window-content { + height: 100%; + padding: 5px; + overflow-y: hidden; } - -.worldbuilding.sheet .profile-img { - flex: 0 0 100px; - height: 100px; - margin-right: 10px; +.worldbuilding .sheet-header { + height: 100px; + overflow: hidden; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + margin-bottom: 10px; } - -.worldbuilding.sheet .header-fields { - flex: 1; - height: 100px; +.worldbuilding .sheet-header .profile-img { + flex: 0 0 100px; + height: 100px; + margin-right: 10px; } - -.worldbuilding.sheet .charname { - height: 60px; - padding: 5px; - margin: 0; - border-bottom: 0; +.worldbuilding .sheet-header .header-fields { + flex: 1; + height: 100px; } -.worldbuilding.sheet .charname input { - width: 100%; - height: 100%; - margin: 0; +.worldbuilding .sheet-header h1.charname { + height: 50px; + padding: 0px; + margin: 5px 0; + border-bottom: 0; } - -.worldbuilding.sheet .resource { - height: 40px; - width: 50%; - padding: 3px 10px; - float: left; +.worldbuilding .sheet-header h1.charname input { + width: 100%; + height: 100%; + margin: 0; } -.worldbuilding.sheet .resource input { - width: 100px; - height: 28px; +.worldbuilding .resource { + width: 50%; + height: 40px; + margin-top: 10px; + float: left; + text-align: center; } - -/* Navigation Tabs */ -.worldbuilding.sheet .tabs { - flex: 0 0 40px; - border-top: 1px solid #AAA; - border-bottom: 1px solid #AAA; +.worldbuilding .resource input { + width: 100px; + height: 28px; } - -.worldbuilding.sheet .tabs .item { - line-height: 40px; - font-weight: bold; +.worldbuilding .tabs { + height: 40px; + border-top: 1px solid #AAA; + border-bottom: 1px solid #AAA; } - -.worldbuilding.sheet .tabs .item.active { - text-decoration: underline; - text-shadow: none; +.worldbuilding .tabs .item { + line-height: 40px; + font-weight: bold; } - -/* Content Tabs */ -.worldbuilding.sheet .sheet-body { - height: calc(100% - 160px); +.worldbuilding .tabs .item.active { + text-decoration: underline; + text-shadow: none; } -.worldbuilding.sheet .sheet-body .tab { - height: 100%; +.worldbuilding .sheet-body { + overflow: hidden; } -.worldbuilding.sheet .sheet-body .editor { - width: 100%; - height: 100%; +.worldbuilding .sheet-body .tab { + height: 100%; + overflow-y: auto; } - - -/* Items */ -.worldbuilding.sheet .items-list { - list-style: none; - margin: 7px 0; - padding: 0; - overflow-y: auto; +.worldbuilding .editor, +.worldbuilding .editor-content { + height: 100%; } -.worldbuilding.sheet .items-list .item { - height: 30px; - line-height: 24px; - padding: 3px 0; - border-bottom: 1px solid #BBB; +.worldbuilding .items-list { + list-style: none; + margin: 7px 0; + padding: 0; + overflow-y: auto; } -.worldbuilding.sheet .items-list .item img { - flex: 0 0 24px; - margin-right: 5px; +.worldbuilding .items-list .item { + height: 30px; + line-height: 24px; + padding: 3px 0; + border-bottom: 1px solid #BBB; } -.worldbuilding.sheet .items-list .item-name { - margin: 0; +.worldbuilding .items-list .item img { + flex: 0 0 24px; + margin-right: 5px; } -.worldbuilding.sheet .items-list .item-controls { - flex: 0 0 36px; +.worldbuilding .items-list .item-name { + margin: 0; } - -/* Attributes */ -.worldbuilding.sheet .attributes-header { - padding: 5px; - margin: 5px 0; - background: rgba(0, 0, 0, 0.05); - border: 1px solid #AAA; - border-radius: 2px; - text-align: center; - font-weight: bold; +.worldbuilding .items-list .item-controls { + flex: 0 0 36px; } -.worldbuilding.sheet .attribute-label { - flex: 1.5; +.worldbuilding .attributes-header { + padding: 5px; + margin: 5px 0; + background: rgba(0, 0, 0, 0.05); + border: 1px solid #AAA; + border-radius: 2px; + text-align: center; + font-weight: bold; } -.worldbuilding.sheet .attribute-control { - flex: 0 0 20px; +.worldbuilding .attributes-header .attribute-label { + flex: 1.5; } - -.worldbuilding.sheet .attributes-list { - list-style: none; - margin: 0; - padding: 0; +.worldbuilding .attributes-header .attribute-control { + flex: 0 0 20px; } - -.worldbuilding.sheet .attributes-list li > * { - margin: 0 3px; - height: 28px; - line-height: 24px; - background: transparent; - border: none; - border-radius: 0; - border-bottom: 1px solid #AAA; +.worldbuilding .attributes-list { + list-style: none; + margin: 0; + padding: 0; } - -.worldbuilding.sheet .attribute-value.checkbox { - text-align: center; +.worldbuilding .attributes-list li > * { + margin: 0 3px; + height: 28px; + line-height: 24px; + background: transparent; + border: none; + border-radius: 0; + border-bottom: 1px solid #AAA; +} +.worldbuilding .attributes-list a.attribute-control { + flex: 0 0 20px; + text-align: center; + line-height: 28px; + border: none; +} +.worldbuilding.sheet.actor { + min-width: 560px; + min-height: 420px; +} +.worldbuilding.sheet.item { + min-width: 460px; + min-height: 400px; } - -.worldbuilding.sheet .attributes-list li a.attribute-control { - border: none; -} \ No newline at end of file diff --git a/styles/simple.less b/styles/simple.less new file mode 100644 index 0000000..a0e684a --- /dev/null +++ b/styles/simple.less @@ -0,0 +1,162 @@ +.worldbuilding { + .window-content { + height: 100%; + padding: 5px; + overflow-y: hidden; + } + + .sheet-header { + height: 100px; + overflow: hidden; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + margin-bottom: 10px; + + .profile-img { + flex: 0 0 100px; + height: 100px; + margin-right: 10px; + } + + .header-fields { + flex: 1; + height: 100px; + } + + h1.charname { + height: 50px; + padding: 0px; + margin: 5px 0; + border-bottom: 0; + input { + width: 100%; + height: 100%; + margin: 0; + } + } + } + + .resource { + width: 50%; + height: 40px; + margin-top: 10px; + float: left; + text-align: center; + input { + width: 100px; + height: 28px; + } + } + + /* Sheet Tabs */ + .tabs { + height: 40px; + border-top: 1px solid #AAA; + border-bottom: 1px solid #AAA; + + .item { + line-height: 40px; + font-weight: bold; + } + + .item.active { + text-decoration: underline; + text-shadow: none; + } + } + + .sheet-body { + overflow: hidden; + .tab { + height: 100%; + overflow-y: auto; + } + } + + .editor, .editor-content { + height: 100%; + } + + /* Items List */ + .items-list { + list-style: none; + margin: 7px 0; + padding: 0; + overflow-y: auto; + + .item { + height: 30px; + line-height: 24px; + padding: 3px 0; + border-bottom: 1px solid #BBB; + + img { + flex: 0 0 24px; + margin-right: 5px; + } + } + + .item-name { + margin: 0; + } + + .item-controls { + flex: 0 0 36px; + } + } + + /* Attributes */ + .attributes-header { + padding: 5px; + margin: 5px 0; + background: rgba(0, 0, 0, 0.05); + border: 1px solid #AAA; + border-radius: 2px; + text-align: center; + font-weight: bold; + + .attribute-label { + flex: 1.5; + } + + .attribute-control { + flex: 0 0 20px; + } + } + + .attributes-list { + list-style: none; + margin: 0; + padding: 0; + + li > * { + margin: 0 3px; + height: 28px; + line-height: 24px; + background: transparent; + border: none; + border-radius: 0; + border-bottom: 1px solid #AAA; + } + + a.attribute-control { + flex: 0 0 20px; + text-align: center; + line-height: 28px; + border: none; + } + } +} + +.worldbuilding.sheet.actor { + min-width: 560px; + min-height: 420px; +} + + +.worldbuilding.sheet.item { + min-width: 460px; + min-height: 400px; +} diff --git a/system.json b/system.json index a9c5b73..c4e19fe 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "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.34, + "version": 0.35, "minimumCoreVersion": "0.5.2", "compatibleCoreVersion": "0.5.5", "templateVersion": 2, @@ -17,6 +17,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-034/worldbuilding-release-034.zip", + "download": "https://gitlab.com/foundrynet/worldbuilding/-/archive/release-035/worldbuilding-release-035.zip", "license": "LICENSE.txt" } diff --git a/templates/actor-sheet.html b/templates/actor-sheet.html index 0d8d659..4620fad 100644 --- a/templates/actor-sheet.html +++ b/templates/actor-sheet.html @@ -29,7 +29,7 @@
{{!-- Biography Tab --}} -
+
{{editor content=data.biography target="data.biography" button=true owner=owner editable=editable}}