From d9ec8023388b19ac939994742e65460289808edc Mon Sep 17 00:00:00 2001 From: U~man Date: Fri, 3 Jul 2020 17:13:53 +0200 Subject: [PATCH] ENH: Monster sheet improv --- src/lang/en.json | 1 + src/module/actor/actor-sheet.js | 38 +++++- src/module/actor/character-sheet.js | 29 +--- src/module/actor/entity.js | 15 ++ src/module/actor/monster-sheet.js | 86 ++++++++---- src/module/item/entity.js | 1 - src/scss/actor-base.scss | 125 ++++++++++++++++- src/scss/character.scss | 129 ------------------ src/scss/monster.scss | 64 --------- src/template.json | 1 - .../partials/character-attributes-tab.html | 8 +- .../partials/character-inventory-tab.html | 6 +- .../actors/partials/character-spells-tab.html | 8 -- .../partials/monster-attributes-tab.html | 54 +++----- 14 files changed, 263 insertions(+), 302 deletions(-) diff --git a/src/lang/en.json b/src/lang/en.json index fa0f5cd..a7ff5c8 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -22,6 +22,7 @@ "OSE.Morale": "Morale", "OSE.Retainer": "Retainer", "OSE.Appearing": "NA", + "OSE.Attack": "Attack", "OSE.Loyalty": "Loyalty Rating", "OSE.LoyaltyShort": "LR", diff --git a/src/module/actor/actor-sheet.js b/src/module/actor/actor-sheet.js index d3790e9..f4c59c1 100644 --- a/src/module/actor/actor-sheet.js +++ b/src/module/actor/actor-sheet.js @@ -26,7 +26,7 @@ export class OseActorSheet extends ActorSheet { */ _prepareItems(data) { // Partition items by category - let [inventory, weapons, armors, abilities, spells] = data.items.reduce( + let [items, weapons, armors, abilities, spells] = data.items.reduce( (arr, item) => { // Classify items into types if (item.type === "item") arr[0].push(item); @@ -42,19 +42,44 @@ export class OseActorSheet extends ActorSheet { // Sort spells by level var sortedSpells = {}; for (var i = 0; i < spells.length; i++) { - let lvl = spells[i].data.lvl + let lvl = spells[i].data.lvl; if (!sortedSpells[lvl]) sortedSpells[lvl] = []; sortedSpells[lvl].push(spells[i]); } // Assign and return - data.inventory = inventory; - data.weapons = weapons; - data.armors = armors; - data.spells = sortedSpells; + data.owned = { + items: items, + weapons: weapons, + armors: armors, + }; data.abilities = abilities; + data.spells = sortedSpells; } + _onItemSummary(event) { + event.preventDefault(); + let li = $(event.currentTarget).parents(".item"), + item = this.actor.getOwnedItem(li.data("item-id")), + description = TextEditor.enrichHTML(item.data.data.description); + // Toggle summary + if (li.hasClass("expanded")) { + let summary = li.parents(".item-entry").children(".item-summary"); + summary.slideUp(200, () => summary.remove()); + } else { + let div = $(`
${description}
`); + li.parents(".item-entry").append(div.hide()); + div.slideDown(200); + } + li.toggleClass("expanded"); + } + + activateListeners(html) { + // Item summaries + html + .find(".item .item-name h4") + .click((event) => this._onItemSummary(event)); + html.find(".saving-throw .attribute-name a").click((ev) => { let actorObject = this.actor; let element = event.currentTarget; @@ -91,7 +116,6 @@ export class OseActorSheet extends ActorSheet { item.roll(); }); - super.activateListeners(html); } diff --git a/src/module/actor/character-sheet.js b/src/module/actor/character-sheet.js index 002606a..493674e 100644 --- a/src/module/actor/character-sheet.js +++ b/src/module/actor/character-sheet.js @@ -57,23 +57,6 @@ export class OseActorSheetCharacter extends OseActorSheet { /* -------------------------------------------- */ - _onItemSummary(event) { - event.preventDefault(); - let li = $(event.currentTarget).parents(".item"), - item = this.actor.getOwnedItem(li.data("item-id")), - description = TextEditor.enrichHTML(item.data.data.description); - // Toggle summary - if (li.hasClass("expanded")) { - let summary = li.parents(".item-entry").children(".item-summary"); - summary.slideUp(200, () => summary.remove()); - } else { - let div = $(`
${description}
`); - li.parents(".item-entry").append(div.hide()); - div.slideDown(200); - } - li.toggleClass("expanded"); - } - async _onQtChange(event) { event.preventDefault(); const itemId = event.currentTarget.closest(".item").dataset.itemId; @@ -133,11 +116,6 @@ export class OseActorSheetCharacter extends OseActorSheet { .click((ev) => ev.target.select()) .change(this._onQtChange.bind(this)); - // Item summaries - html - .find(".item .item-name h4") - .click((event) => this._onItemSummary(event)); - html.find(".ability-score .attribute-name a").click((ev) => { let actorObject = this.actor; let element = event.currentTarget; @@ -145,6 +123,13 @@ export class OseActorSheetCharacter extends OseActorSheet { actorObject.rollCheck(score, { event: event }); }); + html.find(".attack a").click(ev => { + let actorObject = this.actor; + let element = event.currentTarget; + let attack = element.parentElement.parentElement.dataset.attack; + actorObject.rollAttack(attack, { event: event }); + }) + // Handle default listeners last so system listeners are triggered first super.activateListeners(html); } diff --git a/src/module/actor/entity.js b/src/module/actor/entity.js index f3fd59f..6c4f2ba 100644 --- a/src/module/actor/entity.js +++ b/src/module/actor/entity.js @@ -42,6 +42,21 @@ export class OseActor extends Actor { }); } + rollAttack(attack, options={}) { + const label = game.i18n.localize(`OSE.${attack}`); + const rollParts = ['1d20']; + + // Roll and return + return OseDice.Roll({ + event: options.event, + parts: rollParts, + data: this.data, + speaker: ChatMessage.getSpeaker({ actor: this }), + flavor: `${label} ${game.i18n.localize('OSE.Attack')}`, + title: `${label} ${game.i18n.localize('OSE.Attack')}`, + }); + } + computeModifiers() { let _valueToMod = (val) => { switch (val) { diff --git a/src/module/actor/monster-sheet.js b/src/module/actor/monster-sheet.js index e799ed2..54ee4ec 100644 --- a/src/module/actor/monster-sheet.js +++ b/src/module/actor/monster-sheet.js @@ -45,25 +45,42 @@ export class OseActorSheetMonster extends OseActorSheet { return data; } - _onItemSummary(event) { - event.preventDefault(); - let li = $(event.currentTarget).parents(".item"), - item = this.actor.getOwnedItem(li.data("item-id")), - description = TextEditor.enrichHTML(item.data.data.description); - // Toggle summary - if ( li.hasClass("expanded") ) { - let summary = li.parents('.item-entry').children(".item-summary"); - summary.slideUp(200, () => summary.remove()); - } else { - let div = $(`
${description}
`); - li.parents('.item-entry').append(div.hide()); - div.slideDown(200); - } - li.toggleClass("expanded"); - } - /* -------------------------------------------- */ + async _chooseItemType( + choices = ['weapon', 'armor', 'shield', 'gear'], + ) { + let templateData = { upper: '', lower: '', types: choices }, + dlg = await renderTemplate( + 'templates/sidebar/entity-create.html', + templateData, + ); + //Create Dialog window + return new Promise((resolve) => { + new Dialog({ + title: '', + content: dlg, + buttons: { + ok: { + label: game.i18n.localize('OSE.Ok'), + icon: '', + callback: (html) => { + resolve({ + type: html.find('select[name="type"]').val(), + name: html.find('input[name="name"]').val(), + }); + }, + }, + cancel: { + icon: '', + label: game.i18n.localize('OSE.Cancel'), + }, + }, + default: 'ok', + }).render(true); + }); + } + /** * Activate event listeners using the prepared sheet HTML * @param html {HTML} The prepared HTML object ready to be rendered into the DOM @@ -90,17 +107,32 @@ export class OseActorSheetMonster extends OseActorSheet { event.preventDefault(); const header = event.currentTarget; const type = header.dataset.type; - const itemData = { - name: `New ${type.capitalize()}`, - type: type, - data: duplicate(header.dataset), - }; - delete itemData.data["type"]; - return this.actor.createOwnedItem(itemData); - }); - html.find(".item-name").click((event) => { - this._onItemSummary(event); + // item creation helper func + let createItem = function ( + type, + name = `New ${type.capitalize()}`, + ) { + const itemData = { + name: name ? name : `New ${type.capitalize()}`, + type: type, + data: duplicate(header.dataset), + }; + delete itemData.data['type']; + return itemData; + }; + + // Getting back to main logic + if (type == 'choice') { + const choices = header.dataset.choices.split(','); + this._chooseItemType(choices).then((dialogInput) => { + const itemData = createItem(dialogInput.type, dialogInput.name); + this.actor.createOwnedItem(itemData, {}); + }); + return; + } + const itemData = createItem(type); + return this.actor.createOwnedItem(itemData, {}); }); // Handle default listeners last so system listeners are triggered first diff --git a/src/module/item/entity.js b/src/module/item/entity.js index 8c979a3..78edbf4 100644 --- a/src/module/item/entity.js +++ b/src/module/item/entity.js @@ -55,7 +55,6 @@ export class OseItem extends Item { item: this.data, data: this.getChatData(), labels: this.labels, - hasAttack: this.hasAttack, isHealing: this.isHealing, hasDamage: this.hasDamage, isSpell: this.data.type === "spell", diff --git a/src/scss/actor-base.scss b/src/scss/actor-base.scss index 600bef9..2469c37 100644 --- a/src/scss/actor-base.scss +++ b/src/scss/actor-base.scss @@ -32,7 +32,7 @@ padding: 0; } } - + /* Header Summary Details */ .header-details { h1 { @@ -84,7 +84,7 @@ padding: 2px 10px 0; margin-left: -5px; text-indent: 4px; - background: url('/ui/parchment.jpg'); + background: url("/ui/parchment.jpg"); border-top-right-radius: 4px; border-top-left-radius: 80px; box-shadow: 0 0 6px 1px $colorDark; @@ -163,6 +163,127 @@ } } } + .inventory { + overflow: auto; + .header-spells { + line-height: 30px; + } + .item-titles { + text-align: center; + padding-top: 4px; + .item-name { + text-align: left; + text-indent: 8px; + } + font-weight: 300; + font-size: 12px; + background: $colorDark; + color: white; + input { + color: white; + margin: auto; + } + } + .item-list { + list-style: none; + margin: 0; + padding: 0; + & > * { + line-height: 30px; + } + .item-summary { + font-size: 13px; + padding: 0 4px; + line-height: 20px; + } + .item-header { + @extend %header-field !optional; + padding: 0px; + margin-bottom: 0px; + } + .item-entry { + &:nth-child(even) { + .item { + background: rgba(0, 0, 0, 0.1); + } + } + } + .item { + line-height: 30px; + height: 30px; + overflow: hidden; + } + .item-equipped { + grid-area: item-equipped; + justify-self: center; + } + .item-name { + text-indent: 8px; + text-align: left; + overflow: hidden; + height: 30px; + margin: 0; + line-height: 30px; + &:hover .item-image { + background-image: url("/icons/svg/d20-grey.svg") !important; + cursor: pointer; + } + .item-image { + flex-basis: 30px; + flex-grow: 0; + background-size: contain; + background-repeat: no-repeat; + &:hover { + background-image: url("/icons/svg/d20-black.svg") !important; + } + } + h4 { + margin: 0; + } + } + } + .field-longer { + text-indent: 8px; + text-align: left; + flex-basis: 150px; + font-size: 12px; + flex-grow: 0; + } + .field-long { + flex-basis: 65px; + flex-grow: 0; + text-align: center; + font-size: 12px; + } + .field-short { + font-size: 12px; + flex-basis: 45px; + flex-grow: 0; + text-align: center; + &.quantity { + display: flex; + input { + margin: 3px 0; + border-bottom: none; + } + } + } + .item-controls { + font-size: 12px; + flex-basis: 60px; + flex-grow: 0; + text-align: right; + margin-right: 4px; + .item-unequipped { + color: rgba(0, 0, 0, 0.2); + } + } + &.spells { + .item-controls { + flex-basis: 30px; + } + } + } .editor { height: 300px; padding: 4px; diff --git a/src/scss/character.scss b/src/scss/character.scss index bba8afe..b91b422 100644 --- a/src/scss/character.scss +++ b/src/scss/character.scss @@ -64,135 +64,6 @@ background-position: bottom; } } - .inventory { - overflow: auto; - .header-spells { - line-height: 30px; - } - .item-titles { - text-align: center; - margin-top: 1px; - padding-top: 2px; - .item-name { - text-align: left; - text-indent: 8px; - } - font-weight: 300; - font-size: 12px; - background: $colorDark; - color: white; - input { - color: white; - margin: auto; - } - } - .item-list { - list-style: none; - margin: 0; - padding: 0; - &>* { - line-height: 30px; - } - .item-summary { - font-size: 13px; - padding: 0 4px; - line-height: 20px; - } - .item-header { - @extend %header-field !optional; - padding: 0px; - margin-bottom: 0px; - } - .item-entry { - &:nth-child(even) { - .item { - background: rgba(0, 0, 0, 0.1); - } - } - } - .item { - line-height: 30px; - height: 30px; - overflow: hidden; - } - .item-equipped { - grid-area: item-equipped; - justify-self: center; - } - .item-name { - text-indent: 8px; - text-align: left; - overflow: hidden; - height: 30px; - margin: 0; - line-height: 30px; - &:hover .item-image { - background-image: url("/icons/svg/d20-grey.svg") !important; - cursor: pointer; - } - .item-image { - flex-basis: 30px; - flex-grow: 0; - background-size: contain; - background-repeat: no-repeat; - &:hover { - background-image: url("/icons/svg/d20-black.svg") !important; - } - } - h4 { - margin: 0; - } - } - } - .field-longer { - text-indent: 8px; - text-align: left; - flex-basis: 150px; - font-size: 12px; - flex-grow: 0; - } - .field-long { - flex-basis: 65px; - flex-grow: 0; - text-align: center; - font-size: 12px; - } - .field-short { - font-size: 12px; - flex-basis: 45px; - flex-grow: 0; - text-align: center; - &.quantity { - display: flex; - input { - margin: 3px 0; - border-bottom: none; - } - } - } - .item-controls { - font-size: 12px; - flex-basis: 60px; - flex-grow: 0; - text-align: right; - margin-right: 4px; - .item-unequipped { - color: rgba(0, 0, 0, 0.2); - } - } - &.spells { - .item-controls { - flex-basis: 30px; - } - } - } - } - - /* ----------------------------------------- */ - /* Inventory */ - /* ----------------------------------------- */ - .inventory { - } /* ----------------------------------------- */ /* Item Controls */ diff --git a/src/scss/monster.scss b/src/scss/monster.scss index 5654c8d..5cd0557 100644 --- a/src/scss/monster.scss +++ b/src/scss/monster.scss @@ -6,68 +6,4 @@ height: 300px; } } - .abilities { - .panel-content { - height: 230px; - overflow: auto; - } - } - .attribute-row { - padding: 2px; - .abilities { - margin: 2px; - } - } - - .inventory { - .item-entry { - padding: 0; - margin: 0; - list-style: none; - .item { - .item-image { - flex: 0 0 30px; - height: 30px; - background-size: cover; - } - .item-name { - line-height: 30px; - height: 30px; - overflow: hidden; - h4 { - text-indent: 4px; - margin: 0; - cursor: pointer; - &:hover { - color: whitesmoke; - background: linear-gradient( - 45deg, - rgba(0, 0, 0, 0.5), - transparent - ); - } - } - } - .item-controls { - line-height: 30px; - flex: 0 0 32px; - margin: 0 3px; - .fas { - color: $colorTan; - font-size: 12px; - &:hover { - color: $colorDark; - } - } - } - } - .item-summary { - font-size: 13px; - padding: 0 4px; - } - &:nth-child(odd) { - background: rgba(0, 0, 0, 0.1); - } - } - } } diff --git a/src/template.json b/src/template.json index 84ae158..e9aebb5 100644 --- a/src/template.json +++ b/src/template.json @@ -43,7 +43,6 @@ "spellcaster": { "spells": { "enabled": false, - "dc": 0, "1": { "value": 0, "max": 0 diff --git a/src/templates/actors/partials/character-attributes-tab.html b/src/templates/actors/partials/character-attributes-tab.html index 2a09664..df6db7a 100644 --- a/src/templates/actors/partials/character-attributes-tab.html +++ b/src/templates/actors/partials/character-attributes-tab.html @@ -113,8 +113,8 @@
- - - {{!-- Equipment --}} -
-
-

{{localize 'OSE.panel.equipment'}}

-
- {{#if owner}} - - {{/if}} -
-
-
    -
    - {{#each inventory as |item|}} + {{#each owned as |section| }} + {{#each section as |item|}}
  • @@ -120,18 +105,19 @@
    - {{#if ../owner}} - - {{/if}}
  • {{/each}} -
    -
+ {{/each}} + +
{{!-- Saving throws --}}