From d55ec2434273d804c8743f221b85f26cdca465a2 Mon Sep 17 00:00:00 2001 From: U~man Date: Mon, 29 Jun 2020 21:52:50 +0200 Subject: [PATCH 01/19] WIP: Settings and revamp --- src/lang/en.json | 25 +++++++++--- src/module/actor/actor-sheet.js | 35 +++++++++++++++++ src/module/actor/character-sheet.js | 33 +++------------- src/module/actor/monster-sheet.js | 36 +++--------------- src/module/settings.js | 38 +++++++++++++++++++ src/ose.js | 5 +++ src/scss/actor-base.scss | 5 ++- src/template.json | 15 +++++++- .../partials/character-attributes-tab.html | 24 ++++++++++-- .../actors/partials/character-spells-tab.html | 11 +++++- .../actors/partials/monster-header.html | 2 + 11 files changed, 156 insertions(+), 73 deletions(-) create mode 100644 src/module/actor/actor-sheet.js create mode 100644 src/module/settings.js diff --git a/src/lang/en.json b/src/lang/en.json index 7089dbe..50bd5af 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -28,15 +28,15 @@ "OSE.scores.cha.short": "CHA", "OSE.saves.death.short": "D", - "OSE.saves.death.long": "Death", + "OSE.saves.death.long": "Death, Poison", "OSE.saves.wands.short": "W", - "OSE.saves.wands.long": "Wands", + "OSE.saves.wands.long": "Wand", "OSE.saves.paralysis.short": "P", - "OSE.saves.paralysis.long": "Paralysis", + "OSE.saves.paralysis.long": "Paralysis, Petrify", "OSE.saves.breath.short": "B", - "OSE.saves.breath.long": "Breath", + "OSE.saves.breath.long": "Dragon Breath", "OSE.saves.spells.short": "S", - "OSE.saves.spells.long": "Spells", + "OSE.saves.spells.long": "Rod, Staff, Spell", "OSE.Health": "Hit Points", "OSE.HealthShort": "HP", @@ -49,6 +49,10 @@ "OSE.ArmorClassShort": "AC", "OSE.SpellDC": "DC", "OSE.Thac0": "THAC0", + "OSE.MeleeShort": "MEL", + "OSE.Melee": "Melee", + "OSE.MissileShort": "MIS", + "OSE.Missile": "Missile", "OSE.Initiative": "Initiative", "OSE.InitiativeShort": "INIT", "OSE.Attacks": "Attacks Usable per Round", @@ -61,5 +65,14 @@ "OSE.category.notes": "Notes", "OSE.panel.abilities": "Abilities", - "OSE.panel.equipment": "Equipment" + "OSE.panel.equipment": "Equipment", + + "OSE.Setting.IndividualInit": "Individual Initiative", + "OSE.Setting.IndividualInitHint": "Initiative is rolled for each actor and modified by its DEX score", + "OSE.Setting.AscendingAC": "Ascending Armor Class", + "OSE.Setting.AscendingACHint": "The more the better", + "OSE.Setting.Morale": "Enable Monster Morale checks", + "OSE.Setting.MoraleHint": "Morale Rating is shown on monster sheets", + "OSE.Setting.THAC0Attacks": "Attacks with THAC0", + "OSE.Setting.THAC0AttacksHint": "Attacks are resolved using the THAC0 value" } \ No newline at end of file diff --git a/src/module/actor/actor-sheet.js b/src/module/actor/actor-sheet.js new file mode 100644 index 0000000..c42789c --- /dev/null +++ b/src/module/actor/actor-sheet.js @@ -0,0 +1,35 @@ +import { OseActor } from "./entity.js"; + +export class OseActorSheet extends ActorSheet { + constructor(...args) { + super(...args); + } + /* -------------------------------------------- */ + + // Override to set resizable initial size + async _renderInner(...args) { + const html = await super._renderInner(...args); + this.form = html[0]; + + // Resize resizable classes + let resizable = html.find('.resizable'); + if (resizable.length == 0) { + return; + } + resizable.each((_, el) => { + let heightDelta = this.position.height - (this.options.height); + el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; + }); + return html; + } + + async _onResize(event) { + super._onResize(event); + let html = $(event.path); + let resizable = html.find('.resizable'); + resizable.each((_, el) => { + let heightDelta = this.position.height - (this.options.height); + el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; + }); + } +} \ No newline at end of file diff --git a/src/module/actor/character-sheet.js b/src/module/actor/character-sheet.js index f99fa3b..4ee2145 100644 --- a/src/module/actor/character-sheet.js +++ b/src/module/actor/character-sheet.js @@ -1,9 +1,10 @@ import { OseActor } from "./entity.js"; +import { OseActorSheet } from "./actor-sheet.js"; /** * Extend the basic ActorSheet with some very simple modifications */ -export class OseActorSheetCharacter extends ActorSheet { +export class OseActorSheetCharacter extends OseActorSheet { constructor(...args) { super(...args); } @@ -31,22 +32,6 @@ export class OseActorSheetCharacter extends ActorSheet { }); } - /* -------------------------------------------- */ - - // Override to set resizable initial size - async _renderInner(...args) { - const html = await super._renderInner(...args); - this.form = html[0]; - - // Resize resizable classes - let resizable = html.find('.resizable'); - resizable.each((_, el) => { - let heightDelta = this.position.height - (this.options.height); - el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; - }); - return html; - } - /** * Prepare data for rendering the Actor sheet * The prepared data object contains both the actor data as well as additional sheet options @@ -62,7 +47,9 @@ export class OseActorSheetCharacter extends ActorSheet { // Prepare owned items this._prepareItems(data); - // DEBUG + // Settings + data.config.individualInit = game.settings.get('ose', 'individualInit'); + return data; } @@ -149,14 +136,4 @@ export class OseActorSheetCharacter extends ActorSheet { // Handle default listeners last so system listeners are triggered first super.activateListeners(html); } - - async _onResize(event) { - super._onResize(event); - let html = $(event.path); - let resizable = html.find('.resizable'); - resizable.each((_, el) => { - let heightDelta = this.position.height - (this.options.height); - el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; - }); - } } diff --git a/src/module/actor/monster-sheet.js b/src/module/actor/monster-sheet.js index 4918b4a..87c97ec 100644 --- a/src/module/actor/monster-sheet.js +++ b/src/module/actor/monster-sheet.js @@ -1,9 +1,10 @@ import { OseActor } from "./entity.js"; +import { OseActorSheet } from "./actor-sheet.js"; /** * Extend the basic ActorSheet with some very simple modifications */ -export class OseActorSheetMonster extends ActorSheet { +export class OseActorSheetMonster extends OseActorSheet { constructor(...args) { super(...args); } @@ -31,25 +32,6 @@ export class OseActorSheetMonster extends ActorSheet { }); } - /* -------------------------------------------- */ - - // Override to set resizable initial size - async _renderInner(...args) { - const html = await super._renderInner(...args); - this.form = html[0]; - - // Resize resizable classes - let resizable = html.find('.resizable'); - if (resizable.length == 0) { - return; - } - resizable.each((_, el) => { - let heightDelta = this.position.height - (this.options.height); - el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; - }); - return html; - } - /** * Prepare data for rendering the Actor sheet * The prepared data object contains both the actor data as well as additional sheet options @@ -62,7 +44,9 @@ export class OseActorSheetMonster extends ActorSheet { // Prepare owned items this._prepareItems(data); - // DEBUG + // Settings + data.config.morale = game.settings.get('ose', 'morale'); + return data; } @@ -151,14 +135,4 @@ export class OseActorSheetMonster extends ActorSheet { // Handle default listeners last so system listeners are triggered first super.activateListeners(html); } - - async _onResize(event) { - super._onResize(event); - let html = $(event.path); - let resizable = html.find('.resizable'); - resizable.each((_, el) => { - let heightDelta = this.position.height - (this.options.height); - el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; - }); - } } diff --git a/src/module/settings.js b/src/module/settings.js new file mode 100644 index 0000000..1f42d21 --- /dev/null +++ b/src/module/settings.js @@ -0,0 +1,38 @@ +export const registerSettings = function () { + game.settings.register('ose', 'individualInit', { + name: game.i18n.localize('OSE.Setting.IndividualInit'), + hint: game.i18n.localize('OSE.Setting.IndividualInitHint'), + default: false, + scope: 'world', + type: Boolean, + config: true + }); + + game.settings.register('ose', 'ascendingAC', { + name: game.i18n.localize('OSE.Setting.AscendingAC'), + hint: game.i18n.localize('OSE.Setting.AscendingACHint'), + default: false, + scope: 'world', + type: Boolean, + config: true + }); + + game.settings.register('ose', 'morale', { + name: game.i18n.localize('OSE.Setting.Morale'), + hint: game.i18n.localize('OSE.Setting.MoraleHint'), + default: false, + scope: 'world', + type: Boolean, + config: true + }); + + game.settings.register('ose', 'thac0Attacks', { + name: game.i18n.localize('OSE.Setting.THAC0Attacks'), + hint: game.i18n.localize('OSE.Setting.THAC0AttacksHint'), + default: false, + scope: 'world', + type: Boolean, + config: true + }); +} + \ No newline at end of file diff --git a/src/ose.js b/src/ose.js index 5edf4c1..33ecae6 100644 --- a/src/ose.js +++ b/src/ose.js @@ -6,6 +6,7 @@ import { preloadHandlebarsTemplates } from "./module/preloadTemplates.js"; import { OseActor } from "./module/actor/entity.js"; import { OseItem } from "./module/item/entity.js"; import { OSE } from "./module/config.js"; +import { registerSettings } from './module/settings.js'; // Handlebars template helpers Handlebars.registerHelper("eq", function (a, b) { @@ -35,6 +36,10 @@ Hooks.once("init", async function () { }; CONFIG.OSE = OSE; + + // Register custom system settings + registerSettings(); + CONFIG.Actor.entityClass = OseActor; CONFIG.Item.entityClass = OseItem; diff --git a/src/scss/actor-base.scss b/src/scss/actor-base.scss index 628191e..3009bfe 100644 --- a/src/scss/actor-base.scss +++ b/src/scss/actor-base.scss @@ -10,6 +10,9 @@ .panel { border: 1px solid $colorDark; + &.spells { + border: 0; + } .panel-title { color: whitesmoke; background: $colorDark; @@ -95,7 +98,7 @@ margin: 0; padding: 0; .attribute { - margin: 10px; + margin: 10px 2px; border: 1px solid $colorTan; .attribute-name { color: whitesmoke; diff --git a/src/template.json b/src/template.json index bf2f7e1..7aa262b 100644 --- a/src/template.json +++ b/src/template.json @@ -9,7 +9,8 @@ "alignment": "", "literate": false, "level": 1, - "xp": 0 + "xp": 0, + "xpmod": 0 }, "scores": { "str": { @@ -63,6 +64,10 @@ "lvl5": { "value": 0, "max": 0 + }, + "lvl6": { + "value": 0, + "max": 0 } }, "hp": { @@ -76,7 +81,9 @@ }, "thac0": { "value": 19, - "mod": 0 + "mod": 0, + "missile": 0, + "melee": 0 }, "saves": { "D": 10, @@ -153,6 +160,10 @@ "lvl5": { "value": 0, "max": 0 + }, + "lvl6": { + "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 c87817d..03265fe 100644 --- a/src/templates/actors/partials/character-attributes-tab.html +++ b/src/templates/actors/partials/character-attributes-tab.html @@ -1,7 +1,7 @@
-
+

{{localize 'OSE.category.spells'}}

diff --git a/src/templates/actors/partials/monster-header.html b/src/templates/actors/partials/monster-header.html index 5fb5835..7e78968 100644 --- a/src/templates/actors/partials/monster-header.html +++ b/src/templates/actors/partials/monster-header.html @@ -31,10 +31,12 @@ placeholder="{{ localize 'OSE.Experience' }}" /> + {{#if config.morale}}
  • + {{/if}}
    \ No newline at end of file From cb7fd49d558d6092fedf80b3b5eb98911119cd61 Mon Sep 17 00:00:00 2001 From: U~man Date: Mon, 29 Jun 2020 22:35:25 +0200 Subject: [PATCH 02/19] ENH: Template rework, more settings, Tweaks --- src/lang/en.json | 5 +- src/module/actor/actor-sheet.js | 39 ++++++++ src/module/dialog/entity-tweaks.js | 58 ++++++++++++ src/module/settings.js | 9 ++ src/template.json | 88 +++++++------------ src/templates/actors/character-sheet.html | 4 + .../actors/dialogs/tweaks-dialog.html | 20 +++++ src/templates/actors/monster-sheet.html | 4 + .../partials/character-attributes-tab.html | 20 ++--- .../partials/monster-attributes-tab.html | 10 +-- 10 files changed, 187 insertions(+), 70 deletions(-) create mode 100644 src/module/dialog/entity-tweaks.js create mode 100644 src/templates/actors/dialogs/tweaks-dialog.html diff --git a/src/lang/en.json b/src/lang/en.json index 50bd5af..382cc4b 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -57,6 +57,7 @@ "OSE.InitiativeShort": "INIT", "OSE.Attacks": "Attacks Usable per Round", "OSE.AttacksShort": "ATT", + "OSE.Spellcaster": "Spellcaster", "OSE.category.attributes": "Attributes", @@ -74,5 +75,7 @@ "OSE.Setting.Morale": "Enable Monster Morale checks", "OSE.Setting.MoraleHint": "Morale Rating is shown on monster sheets", "OSE.Setting.THAC0Attacks": "Attacks with THAC0", - "OSE.Setting.THAC0AttacksHint": "Attacks are resolved using the THAC0 value" + "OSE.Setting.THAC0AttacksHint": "Attacks are resolved using the THAC0 value, not compatible with AAC", + "OSE.Setting.VariableWeaponDamage": "Variable Weapon Damage", + "OSE.Setting.VariableWeaponDamageHint": "Weapons have different damage dice" } \ No newline at end of file diff --git a/src/module/actor/actor-sheet.js b/src/module/actor/actor-sheet.js index c42789c..6168c30 100644 --- a/src/module/actor/actor-sheet.js +++ b/src/module/actor/actor-sheet.js @@ -1,4 +1,5 @@ import { OseActor } from "./entity.js"; +import { OseEntityTweaks } from "../dialog/entity-tweaks.js"; export class OseActorSheet extends ActorSheet { constructor(...args) { @@ -6,6 +7,13 @@ export class OseActorSheet extends ActorSheet { } /* -------------------------------------------- */ + activateListeners(html) { + super.activateListeners(html); + html.find('.saving-throw .attribute-name').click(ev => { + console.log('hey'); + }) + } + // Override to set resizable initial size async _renderInner(...args) { const html = await super._renderInner(...args); @@ -32,4 +40,35 @@ export class OseActorSheet extends ActorSheet { el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; }); } + + + _onConfigureActor(event) { + event.preventDefault(); + new OseEntityTweaks(this.actor, { + top: this.position.top + 40, + left: this.position.left + (this.position.width - 400) / 2, + }).render(true); + } + + /** + * Extend and override the sheet header buttons + * @override + */ + _getHeaderButtons() { + let buttons = super._getHeaderButtons(); + + // Token Configuration + const canConfigure = game.user.isGM || this.actor.owner; + if (this.options.editable && canConfigure) { + buttons = [ + { + label: 'Tweaks', + class: 'configure-actor', + icon: 'fas fa-dice', + onclick: (ev) => this._onConfigureActor(ev), + }, + ].concat(buttons); + } + return buttons; + } } \ No newline at end of file diff --git a/src/module/dialog/entity-tweaks.js b/src/module/dialog/entity-tweaks.js new file mode 100644 index 0000000..01c03ac --- /dev/null +++ b/src/module/dialog/entity-tweaks.js @@ -0,0 +1,58 @@ +// eslint-disable-next-line no-unused-vars +import { OseActor } from '../actor/entity.js'; + +export class OseEntityTweaks extends FormApplication { + static get defaultOptions() { + const options = super.defaultOptions; + options.id = 'sheet-tweaks'; + options.template = + 'systems/ose/templates/actors/dialogs/tweaks-dialog.html'; + options.width = 380; + return options; + } + + /* -------------------------------------------- */ + + /** + * Add the Entity name into the window title + * @type {String} + */ + get title() { + return `${this.object.name}: OSE Tweaks`; + } + + /* -------------------------------------------- */ + + /** + * Construct and return the data object used to render the HTML template for this form application. + * @return {Object} + */ + getData() { + let data = this.object.data; + if (this.object.data.type === 'character') { + data.isCharacter = true; + } + return data; + } + + /* -------------------------------------------- */ + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + } + + /** + * This method is called upon form submission after form data is validated + * @param event {Event} The initial triggering submission event + * @param formData {Object} The object of validated form data with which to update the object + * @private + */ + async _updateObject(event, formData) { + event.preventDefault(); + // Update the actor + this.object.update(formData); + // Re-draw the updated sheet + this.object.sheet.render(true); + } +} diff --git a/src/module/settings.js b/src/module/settings.js index 1f42d21..00f2f46 100644 --- a/src/module/settings.js +++ b/src/module/settings.js @@ -34,5 +34,14 @@ export const registerSettings = function () { type: Boolean, config: true }); + + game.settings.register('ose', 'variableDamage', { + name: game.i18n.localize('OSE.Setting.VariableWeaponDamage'), + hint: game.i18n.localize('OSE.Setting.VariableWeaponDamageHint'), + default: false, + scope: 'world', + type: Boolean, + config: true + }); } \ No newline at end of file diff --git a/src/template.json b/src/template.json index 7aa262b..f2cd2e6 100644 --- a/src/template.json +++ b/src/template.json @@ -1,7 +1,40 @@ { "Actor": { "types": ["character", "monster"], + "templates": { + "spellcaster": { + "spells": { + "enabled": false, + "dc": 0, + "lvl1": { + "value": 0, + "max": 0 + }, + "lvl2": { + "value": 0, + "max": 0 + }, + "lvl3": { + "value": 0, + "max": 0 + }, + "lvl4": { + "value": 0, + "max": 0 + }, + "lvl5": { + "value": 0, + "max": 0 + }, + "lvl6": { + "value": 0, + "max": 0 + } + } + } + }, "character": { + "templates": ["spellcaster"], "details": { "biography": "", "class": "", @@ -43,33 +76,6 @@ "silver": 0, "copper": 0 }, - "spells": { - "dc": 0, - "lvl1": { - "value": 0, - "max": 0 - }, - "lvl2": { - "value": 0, - "max": 0 - }, - "lvl3": { - "value": 0, - "max": 0 - }, - "lvl4": { - "value": 0, - "max": 0 - }, - "lvl5": { - "value": 0, - "max": 0 - }, - "lvl6": { - "value": 0, - "max": 0 - } - }, "hp": { "hd": "", "value": 20, @@ -103,6 +109,7 @@ "languages": [] }, "monster": { + "templates": ["spellcaster"], "details": { "biography": "", "alignment": "", @@ -138,33 +145,6 @@ "movement": { "base": 0, "encounter": 0 - }, - "spells": { - "dc": 0, - "lvl1": { - "value": 0, - "max": 0 - }, - "lvl2": { - "value": 0, - "max": 0 - }, - "lvl3": { - "value": 0, - "max": 0 - }, - "lvl4": { - "value": 0, - "max": 0 - }, - "lvl5": { - "value": 0, - "max": 0 - }, - "lvl6": { - "value": 0, - "max": 0 - } } } }, diff --git a/src/templates/actors/character-sheet.html b/src/templates/actors/character-sheet.html index a878aa4..1d2ede3 100644 --- a/src/templates/actors/character-sheet.html +++ b/src/templates/actors/character-sheet.html @@ -12,9 +12,11 @@ {{localize "OSE.category.inventory"}} + {{#if data.spells.enabled}} {{localize "OSE.category.spells"}} + {{/if}} {{localize "OSE.category.notes"}} @@ -28,9 +30,11 @@
    {{> "systems/ose/templates/actors/partials/character-inventory-tab.html"}}
    + {{#if data.spells.enabled}}
    {{> "systems/ose/templates/actors/partials/character-spells-tab.html"}}
    + {{/if}}
    {{editor content=data.details.biography target="data.details.biography" button=true owner=owner editable=editable}} diff --git a/src/templates/actors/dialogs/tweaks-dialog.html b/src/templates/actors/dialogs/tweaks-dialog.html new file mode 100644 index 0000000..fe376d4 --- /dev/null +++ b/src/templates/actors/dialogs/tweaks-dialog.html @@ -0,0 +1,20 @@ +
    +
    + +
    + +
    +
    +
    + +
    +
    + \ No newline at end of file diff --git a/src/templates/actors/monster-sheet.html b/src/templates/actors/monster-sheet.html index 9786ce7..88abee4 100644 --- a/src/templates/actors/monster-sheet.html +++ b/src/templates/actors/monster-sheet.html @@ -9,9 +9,11 @@ {{localize "OSE.category.attributes"}} + {{#if data.spells.enabled}} {{localize "OSE.category.spells"}} + {{/if}} {{localize "OSE.category.notes"}} @@ -22,9 +24,11 @@
    {{> "systems/ose/templates/actors/partials/monster-attributes-tab.html"}}
    + {{#if data.spells.enabled}}
    {{> "systems/ose/templates/actors/partials/character-spells-tab.html"}}
    + {{/if}}
    {{editor content=data.details.biography target="data.details.biography" button=true owner=owner editable=editable}} diff --git a/src/templates/actors/partials/character-attributes-tab.html b/src/templates/actors/partials/character-attributes-tab.html index 03265fe..85804b3 100644 --- a/src/templates/actors/partials/character-attributes-tab.html +++ b/src/templates/actors/partials/character-attributes-tab.html @@ -129,32 +129,32 @@ {{!-- Saving throws --}}
      -
    • -

      {{ localize "OSE.saves.death.short" }}

      +
    • +

      {{ localize "OSE.saves.death.short" }}

    • -
    • -

      {{ localize "OSE.saves.wands.short" }}

      +
    • +

      {{ localize "OSE.saves.wands.short" }}

    • -
    • -

      {{ localize "OSE.saves.paralysis.short" }}

      +
    • +

      {{ localize "OSE.saves.paralysis.short" }

    • -
    • -

      {{ localize "OSE.saves.breath.short" }}

      +
    • +

      {{ localize "OSE.saves.breath.short" }}

    • -
    • -

      {{ localize "OSE.saves.spells.short" }}

      +
    • +

      {{ localize "OSE.saves.spells.short" }}

    • diff --git a/src/templates/actors/partials/monster-attributes-tab.html b/src/templates/actors/partials/monster-attributes-tab.html index 3cdd12e..ce21d15 100644 --- a/src/templates/actors/partials/monster-attributes-tab.html +++ b/src/templates/actors/partials/monster-attributes-tab.html @@ -113,31 +113,31 @@
      • -

        {{ localize "OSE.saves.death.short" }}

        +

        {{ localize "OSE.saves.death.short" }}

      • -

        {{ localize "OSE.saves.wands.short" }}

        +

        {{ localize "OSE.saves.wands.short" }}

      • -

        {{ localize "OSE.saves.paralysis.short" }}

        +

        {{ localize "OSE.saves.paralysis.short" }}

      • -

        {{ localize "OSE.saves.breath.short" }}

        +

        {{ localize "OSE.saves.breath.short" }}

      • -

        {{ localize "OSE.saves.spells.short" }}

        +

        {{ localize "OSE.saves.spells.short" }}

      • From 816c4d4a369c0446e8f8ec0a2fdc114c6d32d42e Mon Sep 17 00:00:00 2001 From: U~man Date: Mon, 29 Jun 2020 23:11:04 +0200 Subject: [PATCH 03/19] ENH: Saving throws --- src/lang/en.json | 16 +++- src/module/actor/actor-sheet.js | 10 ++- src/module/actor/entity.js | 27 ++++--- src/module/dice.js | 78 +++++++++++++++++++ src/template.json | 10 +-- .../partials/character-attributes-tab.html | 26 +++---- .../partials/monster-attributes-tab.html | 24 +++--- src/templates/chat/roll-dialog.html | 20 +++++ 8 files changed, 165 insertions(+), 46 deletions(-) create mode 100644 src/module/dice.js create mode 100644 src/templates/chat/roll-dialog.html diff --git a/src/lang/en.json b/src/lang/en.json index 382cc4b..31da6dc 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -2,6 +2,13 @@ "OSE.Edit": "Edit", "OSE.Delete": "Delete", "OSE.Add": "Add", + "OSE.Cancel": "Cancel", + "OSE.Roll": "Roll", + + "OSE.Formula": "Formula", + "OSE.SitMod": "Situational Modifier", + "OSE.RollMod": "Roll Mode", + "OSE.RollExample": "Roll Example", "OSE.Name": "Name", "OSE.Class": "Class", @@ -27,16 +34,17 @@ "OSE.scores.cha.long": "Charisma", "OSE.scores.cha.short": "CHA", + "OSE.SavingThrow": "Saving Throw", "OSE.saves.death.short": "D", "OSE.saves.death.long": "Death, Poison", - "OSE.saves.wands.short": "W", - "OSE.saves.wands.long": "Wand", + "OSE.saves.wand.short": "W", + "OSE.saves.wand.long": "Wand", "OSE.saves.paralysis.short": "P", "OSE.saves.paralysis.long": "Paralysis, Petrify", "OSE.saves.breath.short": "B", "OSE.saves.breath.long": "Dragon Breath", - "OSE.saves.spells.short": "S", - "OSE.saves.spells.long": "Rod, Staff, Spell", + "OSE.saves.spell.short": "S", + "OSE.saves.spell.long": "Rod, Staff, Spell", "OSE.Health": "Hit Points", "OSE.HealthShort": "HP", diff --git a/src/module/actor/actor-sheet.js b/src/module/actor/actor-sheet.js index 6168c30..d9dc311 100644 --- a/src/module/actor/actor-sheet.js +++ b/src/module/actor/actor-sheet.js @@ -8,10 +8,14 @@ export class OseActorSheet extends ActorSheet { /* -------------------------------------------- */ activateListeners(html) { - super.activateListeners(html); - html.find('.saving-throw .attribute-name').click(ev => { - console.log('hey'); + html.find('.saving-throw .attribute-name a').click(ev => { + let actorObject = this.actor; + let element = event.currentTarget; + let save = element.parentElement.parentElement.dataset.save; + actorObject.rollSave(save, { event: event }); }) + + super.activateListeners(html); } // Override to set resizable initial size diff --git a/src/module/actor/entity.js b/src/module/actor/entity.js index 42d55c8..752f305 100644 --- a/src/module/actor/entity.js +++ b/src/module/actor/entity.js @@ -1,20 +1,29 @@ +import { OseDice } from '../dice.js'; + export class OseActor extends Actor { /** * Extends data from base Actor class */ - prepareData() { - super.prepareData(); - return this.data; - } - /* -------------------------------------------- */ + + /* -------------------------------------------- */ /* Socket Listeners and Handlers /* -------------------------------------------- */ - /** @override */ - async createOwnedItem(itemData, options) { - return super.createOwnedItem(itemData, options); - } /* -------------------------------------------- */ /* Rolls */ /* -------------------------------------------- */ + rollSave(save, options = {}) { + const label = game.i18n.localize(`OSE.saves.${save}.long`); + 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.SavingThrow')}`, + title: `${label} ${game.i18n.localize('OSE.SavingThrow')}`, + }); + } } diff --git a/src/module/dice.js b/src/module/dice.js new file mode 100644 index 0000000..0a33078 --- /dev/null +++ b/src/module/dice.js @@ -0,0 +1,78 @@ +export class OseDice { + // eslint-disable-next-line no-unused-vars + static async Roll({ + parts = [], + data = {}, + options = {}, + event = null, + speaker = null, + flavor = null, + title = null, + item = false, + } = {}) { + let rollMode = game.settings.get("core", "rollMode"); + let rolled = false; + let filtered = parts.filter(function (el) { + return el != "" && el; + }); + + const _roll = (form = null, raise = false) => { + // Optionally include a situational bonus + if (form !== null) data["bonus"] = form.bonus.value; + if (data["bonus"]) filtered.push(data["bonus"]); + + const roll = new Roll(filtered.join(""), data).roll(); + // Convert the roll to a chat message and return the roll + rollMode = form ? form.rollMode.value : rollMode; + roll.toMessage( + { + speaker: speaker, + flavor: flavor, + }, + { rollMode } + ); + rolled = true; + return roll; + }; + + const template = "systems/ose/templates/chat/roll-dialog.html"; + let dialogData = { + formula: filtered.join(" "), + data: data, + rollMode: rollMode, + rollModes: CONFIG.Dice.rollModes, + }; + + let buttons = { + ok: { + label: game.i18n.localize("OSE.Roll"), + icon: '', + callback: (html) => { + roll = _roll(html[0].children[0]); + }, + }, + cancel: { + icon: '', + label: game.i18n.localize("OSE.Cancel"), + }, + }; + + if (!item) delete buttons.raise; + + const html = await renderTemplate(template, dialogData); + let roll; + + //Create Dialog window + return new Promise((resolve) => { + new Dialog({ + title: title, + content: html, + buttons: buttons, + default: "ok", + close: () => { + resolve(rolled ? roll : false) + }, + }).render(true); + }); + } +} diff --git a/src/template.json b/src/template.json index f2cd2e6..042ad9f 100644 --- a/src/template.json +++ b/src/template.json @@ -120,11 +120,11 @@ "morale": 0 }, "saves": { - "D": 10, - "W": 10, - "P": 10, - "B": 10, - "S": 10 + "death": 10, + "wand": 10, + "paralysis": 10, + "breath": 10, + "spell": 10 }, "thac0": { "value": 19, diff --git a/src/templates/actors/partials/character-attributes-tab.html b/src/templates/actors/partials/character-attributes-tab.html index 85804b3..44a6fa8 100644 --- a/src/templates/actors/partials/character-attributes-tab.html +++ b/src/templates/actors/partials/character-attributes-tab.html @@ -129,34 +129,34 @@ {{!-- Saving throws --}} diff --git a/src/templates/actors/partials/monster-attributes-tab.html b/src/templates/actors/partials/monster-attributes-tab.html index ce21d15..cfc5b07 100644 --- a/src/templates/actors/partials/monster-attributes-tab.html +++ b/src/templates/actors/partials/monster-attributes-tab.html @@ -112,34 +112,34 @@ {{!-- Saving throws --}} diff --git a/src/templates/chat/roll-dialog.html b/src/templates/chat/roll-dialog.html new file mode 100644 index 0000000..8c7a079 --- /dev/null +++ b/src/templates/chat/roll-dialog.html @@ -0,0 +1,20 @@ +
        +
        + + +
        +
        + + +
        +
        + + +
        +
        \ No newline at end of file From 0be4556bfe913f733723453f3aa952428d484694 Mon Sep 17 00:00:00 2001 From: U~man Date: Tue, 30 Jun 2020 21:05:18 +0200 Subject: [PATCH 04/19] ENH: retainers and items --- src/lang/en.json | 8 +- src/lang/fr.json | 1 - src/module/actor/character-sheet.js | 8 ++ src/module/actor/entity.js | 15 +++ src/template.json | 113 +++++++++--------- .../actors/dialogs/tweaks-dialog.html | 12 ++ .../partials/character-attributes-tab.html | 47 ++++---- .../partials/monster-attributes-tab.html | 9 ++ src/templates/items/armor-sheet.html | 19 +++ src/templates/items/weapon-sheet.html | 19 +++ 10 files changed, 167 insertions(+), 84 deletions(-) create mode 100644 src/templates/items/armor-sheet.html create mode 100644 src/templates/items/weapon-sheet.html diff --git a/src/lang/en.json b/src/lang/en.json index 31da6dc..5e36dbf 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -7,7 +7,7 @@ "OSE.Formula": "Formula", "OSE.SitMod": "Situational Modifier", - "OSE.RollMod": "Roll Mode", + "OSE.RollMode": "Roll Mode", "OSE.RollExample": "Roll Example", "OSE.Name": "Name", @@ -19,8 +19,13 @@ "OSE.Treasure": "Treasure type", "OSE.Size": "Size", "OSE.Morale": "Morale", + "OSE.Retainer": "Retainer", "OSE.Appearing": "NA", + "OSE.Loyalty": "Loyalty Rating", + "OSE.LoyaltyShort": "LR", + + "OSE.AbilityCheck": "Ability Check", "OSE.scores.str.long": "Strength", "OSE.scores.str.short": "STR", "OSE.scores.wis.long": "Wisdom", @@ -52,7 +57,6 @@ "OSE.HitDiceShort": "HD", "OSE.Movement": "Movement", "OSE.MovementShort": "MOV", - "OSE.SpecialMovement": "Special Movement", "OSE.ArmorClass": "Armor Class", "OSE.ArmorClassShort": "AC", "OSE.SpellDC": "DC", diff --git a/src/lang/fr.json b/src/lang/fr.json index 1ff3656..66ee21d 100644 --- a/src/lang/fr.json +++ b/src/lang/fr.json @@ -44,7 +44,6 @@ "OSE.HitDiceShort": "DV", "OSE.Movement": "Mouvement", "OSE.MovementShort": "MOUV", - "OSE.SpecialMovement": "Mouvement Spécial", "OSE.ArmorClass": "Classe d'Armure", "OSE.ArmorClassShort": "CA", "OSE.SpellDC": "DF", diff --git a/src/module/actor/character-sheet.js b/src/module/actor/character-sheet.js index 4ee2145..f60d12d 100644 --- a/src/module/actor/character-sheet.js +++ b/src/module/actor/character-sheet.js @@ -133,6 +133,14 @@ export class OseActorSheetCharacter extends OseActorSheet { // 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; + let score = element.parentElement.parentElement.dataset.score; + actorObject.rollCheck(score, { 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 752f305..5262f04 100644 --- a/src/module/actor/entity.js +++ b/src/module/actor/entity.js @@ -26,4 +26,19 @@ export class OseActor extends Actor { title: `${label} ${game.i18n.localize('OSE.SavingThrow')}`, }); } + + rollCheck(score, options = {}) { + const label = game.i18n.localize(`OSE.scores.${score}.long`); + 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.AbilityCheck')}`, + title: `${label} ${game.i18n.localize('OSE.AbilityCheck')}`, + }); + } } diff --git a/src/template.json b/src/template.json index 042ad9f..e4951c2 100644 --- a/src/template.json +++ b/src/template.json @@ -2,6 +2,36 @@ "Actor": { "types": ["character", "monster"], "templates": { + "common": { + "retainer": { + "enabled": false, + "loyalty": 0 + }, + "hp": { + "hd": "", + "value": 20, + "max": 20 + }, + "ac": { + "value": 0, + "mod": 0 + }, + "thac0": { + "value": 19, + "mod": 0 + }, + "saves": { + "death": 10, + "wand": 10, + "paralysis": 10, + "breath": 10, + "spell": 10 + }, + "movement": { + "base": 0, + "encounter": 0 + } + }, "spellcaster": { "spells": { "enabled": false, @@ -34,7 +64,7 @@ } }, "character": { - "templates": ["spellcaster"], + "templates": ["common", "spellcaster"], "details": { "biography": "", "class": "", @@ -76,32 +106,6 @@ "silver": 0, "copper": 0 }, - "hp": { - "hd": "", - "value": 20, - "max": 20 - }, - "ac": { - "value": 0, - "mod": 0 - }, - "thac0": { - "value": 19, - "mod": 0, - "missile": 0, - "melee": 0 - }, - "saves": { - "D": 10, - "W": 10, - "P": 10, - "B": 10, - "S": 10 - }, - "movement": { - "base": 0, - "encounter": 0 - }, "initative": { "value": 0, "mod": 0 @@ -109,7 +113,7 @@ "languages": [] }, "monster": { - "templates": ["spellcaster"], + "templates": ["common", "spellcaster"], "details": { "biography": "", "alignment": "", @@ -119,45 +123,44 @@ "appearing": "", "morale": 0 }, - "saves": { - "death": 10, - "wand": 10, - "paralysis": 10, - "breath": 10, - "spell": 10 - }, - "thac0": { - "value": 19, - "mod": 0 - }, - "hp": { - "hd": "", - "max": 0, - "value": 0 - }, - "ac": { - "value": 0, - "mod": 0 - }, "attacks": { "value": 1 - }, - "movement": { - "base": 0, - "encounter": 0 } } }, "Item": { - "types": ["item", "spell", "ability"], + "types": ["item", "weapon", "armor", "spell", "ability"], "item": { "description": "", - "quantity": 1, + "quantity": { + "value": 1, + "max": 0 + }, + "cost": 0, + "weight": 0 + }, + "weapon": { + "description": "", + "damage": "1d6", + "qualities": "", + "slow": false, + "melee": true, + "ranged": true, + "cost": 0, + "weight": 0 + }, + "armor": { + "description": "", + "ac": 9, + "aac": 10, + "cost": 0, "weight": 0 }, "spell": { "lvl": 1, - "class": "", + "class": "Magic-User", + "duration": "", + "range": "", "description": "" }, "ability": { diff --git a/src/templates/actors/dialogs/tweaks-dialog.html b/src/templates/actors/dialogs/tweaks-dialog.html index fe376d4..893a513 100644 --- a/src/templates/actors/dialogs/tweaks-dialog.html +++ b/src/templates/actors/dialogs/tweaks-dialog.html @@ -11,6 +11,18 @@ />
    +
    + +
    + +
    +
    -
  • -

    {{ localize "OSE.MeleeShort" }}

    -
    - -
    -
  • -
  • -

    {{ localize "OSE.MissileShort" }}

    -
    - -
    -
  • {{#if config.individualInit}}
  • {{ localize "OSE.InitiativeShort" }}

    @@ -46,6 +32,15 @@
  • {{/if}} + {{#if data.retainer.enabled}} +
  • +

    {{ localize "OSE.LoyaltyShort" }}

    +
    + +
    +
  • + {{/if}}
  • {{ localize "OSE.MovementShort" }}

    @@ -59,33 +54,33 @@ {{!-- Scores --}}
  • + {{#if data.retainer.enabled}} +
  • +

    {{ localize "OSE.LoyaltyShort" }}

    +
    + +
    +
  • + {{/if}}
  • {{ localize "OSE.MovementShort" }}

    diff --git a/src/templates/items/armor-sheet.html b/src/templates/items/armor-sheet.html new file mode 100644 index 0000000..2704d00 --- /dev/null +++ b/src/templates/items/armor-sheet.html @@ -0,0 +1,19 @@ +
    +
    + +
    +

    + +

    +
    +
    +
    + {{editor content=data.description target="data.description" + button=true owner=owner editable=editable}} +
    +
    diff --git a/src/templates/items/weapon-sheet.html b/src/templates/items/weapon-sheet.html new file mode 100644 index 0000000..2704d00 --- /dev/null +++ b/src/templates/items/weapon-sheet.html @@ -0,0 +1,19 @@ +
    +
    + +
    +

    + +

    +
    +
    +
    + {{editor content=data.description target="data.description" + button=true owner=owner editable=editable}} +
    +
    From 611582f22856628ce0cd48f095bad623b8f81b39 Mon Sep 17 00:00:00 2001 From: U~man Date: Tue, 30 Jun 2020 21:58:03 +0200 Subject: [PATCH 05/19] ENH: Items --- src/lang/en.json | 17 +++++++- src/scss/item.scss | 16 ++++++- src/template.json | 4 +- src/templates/items/ability-sheet.html | 19 +++++---- src/templates/items/armor-sheet.html | 43 +++++++++++++++---- src/templates/items/spell-sheet.html | 49 ++++++++++++++++++---- src/templates/items/weapon-sheet.html | 58 ++++++++++++++++++++++---- 7 files changed, 166 insertions(+), 40 deletions(-) diff --git a/src/lang/en.json b/src/lang/en.json index 5e36dbf..015f470 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -89,5 +89,20 @@ "OSE.Setting.THAC0Attacks": "Attacks with THAC0", "OSE.Setting.THAC0AttacksHint": "Attacks are resolved using the THAC0 value, not compatible with AAC", "OSE.Setting.VariableWeaponDamage": "Variable Weapon Damage", - "OSE.Setting.VariableWeaponDamageHint": "Weapons have different damage dice" + "OSE.Setting.VariableWeaponDamageHint": "Weapons have different damage dice", + + "OSE.ItemWeight": "Weight", + "OSE.ItemCost": "Cost", + "OSE.ItemQuantity": "Quantity", + "OSE.ItemRoll": "Roll", + "OSE.WeaponDamage": "Damage", + "OSE.WeaponMelee": "Melee", + "OSE.WeaponMissile": "Missile", + "OSE.WeaponSlow": "Slow", + "OSE.SpellRange": "Range", + "OSE.SpellClass": "Class", + "OSE.SpellDuration": "Duration", + "OSE.SpellLevel": "Level", + "OSE.ArmorAC": "AC", + "OSE.ArmorAAC": "AAC" } \ No newline at end of file diff --git a/src/scss/item.scss b/src/scss/item.scss index c1deb83..3639051 100644 --- a/src/scss/item.scss +++ b/src/scss/item.scss @@ -1,5 +1,17 @@ .ose.sheet.item { - .editor { - height: 255px; + .profile-img { + border: none; } + .sheet-body { + .stats { + flex: 0 0 70px; + border-right: 1px groove rgba(0, 0, 0, 0.2); + } + .editor { + height: 255px; + } + .weapon-editor .editor { + height: 230px; + } + } } \ No newline at end of file diff --git a/src/template.json b/src/template.json index e4951c2..1c5a2c2 100644 --- a/src/template.json +++ b/src/template.json @@ -144,7 +144,7 @@ "damage": "1d6", "qualities": "", "slow": false, - "melee": true, + "missile": true, "ranged": true, "cost": 0, "weight": 0 @@ -161,10 +161,12 @@ "class": "Magic-User", "duration": "", "range": "", + "roll": "", "description": "" }, "ability": { "requirements": "", + "roll": "", "description": "" } } diff --git a/src/templates/items/ability-sheet.html b/src/templates/items/ability-sheet.html index 2704d00..e2c2f77 100644 --- a/src/templates/items/ability-sheet.html +++ b/src/templates/items/ability-sheet.html @@ -3,17 +3,18 @@

    - +

    - {{editor content=data.description target="data.description" - button=true owner=owner editable=editable}} +
    + +
    +
    + {{editor content=data.description target="data.description" button=true + owner=owner editable=editable}} +
    +
  • - + \ No newline at end of file diff --git a/src/templates/items/armor-sheet.html b/src/templates/items/armor-sheet.html index 2704d00..23874f9 100644 --- a/src/templates/items/armor-sheet.html +++ b/src/templates/items/armor-sheet.html @@ -3,17 +3,42 @@

    - +

    - {{editor content=data.description target="data.description" - button=true owner=owner editable=editable}} +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + {{editor content=data.description target="data.description" button=true + owner=owner editable=editable}} +
    +
    - + \ No newline at end of file diff --git a/src/templates/items/spell-sheet.html b/src/templates/items/spell-sheet.html index 2704d00..ce4e1d0 100644 --- a/src/templates/items/spell-sheet.html +++ b/src/templates/items/spell-sheet.html @@ -3,17 +3,48 @@

    - +

    - {{editor content=data.description target="data.description" - button=true owner=owner editable=editable}} +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + {{editor content=data.description target="data.description" button=true + owner=owner editable=editable}} +
    +
    - + \ No newline at end of file diff --git a/src/templates/items/weapon-sheet.html b/src/templates/items/weapon-sheet.html index 2704d00..c4fe94f 100644 --- a/src/templates/items/weapon-sheet.html +++ b/src/templates/items/weapon-sheet.html @@ -3,17 +3,57 @@

    - +

    - {{editor content=data.description target="data.description" - button=true owner=owner editable=editable}} +
    + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + {{editor content=data.description target="data.description" button=true + owner=owner editable=editable}} +
    +
    - + \ No newline at end of file From c07bbb864f869977baf557c2f4699de90000d842 Mon Sep 17 00:00:00 2001 From: U~man Date: Tue, 30 Jun 2020 22:11:20 +0200 Subject: [PATCH 06/19] ENH: Ascending AC --- src/lang/en.json | 1 + src/module/actor/actor-sheet.js | 10 ++ src/module/actor/character-sheet.js | 2 - src/module/actor/monster-sheet.js | 2 - src/template.json | 4 + .../partials/character-attributes-tab.html | 102 ++++++++++++------ .../partials/monster-attributes-tab.html | 59 ++++++---- 7 files changed, 122 insertions(+), 58 deletions(-) diff --git a/src/lang/en.json b/src/lang/en.json index 015f470..a18a895 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -59,6 +59,7 @@ "OSE.MovementShort": "MOV", "OSE.ArmorClass": "Armor Class", "OSE.ArmorClassShort": "AC", + "OSE.AscArmorClassShort": "AAC", "OSE.SpellDC": "DC", "OSE.Thac0": "THAC0", "OSE.MeleeShort": "MEL", diff --git a/src/module/actor/actor-sheet.js b/src/module/actor/actor-sheet.js index d9dc311..f05273f 100644 --- a/src/module/actor/actor-sheet.js +++ b/src/module/actor/actor-sheet.js @@ -7,6 +7,16 @@ export class OseActorSheet extends ActorSheet { } /* -------------------------------------------- */ + getData() { + const data = super.getData(); + + data.config = CONFIG.OSE; + // Settings + data.config.ascendingAC = game.settings.get('ose', 'ascendingAC'); + + return data; + } + activateListeners(html) { html.find('.saving-throw .attribute-name a').click(ev => { let actorObject = this.actor; diff --git a/src/module/actor/character-sheet.js b/src/module/actor/character-sheet.js index f60d12d..144e430 100644 --- a/src/module/actor/character-sheet.js +++ b/src/module/actor/character-sheet.js @@ -38,8 +38,6 @@ export class OseActorSheetCharacter extends OseActorSheet { */ getData() { const data = super.getData(); - - data.config = CONFIG.OSE; for (let [a, score] of Object.entries(data.data.scores)) { data.data.scores[a].label = game.i18n.localize(`OSE.scores.${a}`); diff --git a/src/module/actor/monster-sheet.js b/src/module/actor/monster-sheet.js index 87c97ec..e0820ff 100644 --- a/src/module/actor/monster-sheet.js +++ b/src/module/actor/monster-sheet.js @@ -39,8 +39,6 @@ export class OseActorSheetMonster extends OseActorSheet { getData() { const data = super.getData(); - data.config = CONFIG.OSE; - // Prepare owned items this._prepareItems(data); diff --git a/src/template.json b/src/template.json index 1c5a2c2..2dab957 100644 --- a/src/template.json +++ b/src/template.json @@ -16,6 +16,10 @@ "value": 0, "mod": 0 }, + "aac": { + "value": 0, + "mod": 0 + }, "thac0": { "value": 19, "mod": 0 diff --git a/src/templates/actors/partials/character-attributes-tab.html b/src/templates/actors/partials/character-attributes-tab.html index d5df2b6..540842b 100644 --- a/src/templates/actors/partials/character-attributes-tab.html +++ b/src/templates/actors/partials/character-attributes-tab.html @@ -1,7 +1,8 @@
    • -

      {{ localize "OSE.HealthShort" }}

      +

      {{ localize "OSE.HealthShort" }} +

      @@ -10,11 +11,21 @@
    • -

      {{ localize "OSE.ArmorClassShort" }}

      + {{#if config.ascendingAC}} +

      + {{ localize "OSE.AscArmorClassShort" }}

      - +
      + {{else}} +

      + {{ localize "OSE.ArmorClassShort" }}

      +
      + +
      + {{/if}}
    • {{ localize "OSE.Thac0" }}

      @@ -25,27 +36,29 @@
    • {{#if config.individualInit}}
    • -

      {{ localize "OSE.InitiativeShort" }}

      +

      + {{ localize "OSE.InitiativeShort" }}

      - +
    • {{/if}} {{#if data.retainer.enabled}}
    • -

      {{ localize "OSE.LoyaltyShort" }}

      +

      {{ localize "OSE.LoyaltyShort" }} +

      - +
    • {{/if}}
    • {{ localize "OSE.MovementShort" }}

      - +
    @@ -55,34 +68,46 @@ @@ -92,7 +117,8 @@

    {{localize 'OSE.panel.abilities'}}

    {{#if owner}} - + {{/if}}
    @@ -125,33 +151,39 @@ diff --git a/src/templates/actors/partials/monster-attributes-tab.html b/src/templates/actors/partials/monster-attributes-tab.html index 810aaa4..de5c26c 100644 --- a/src/templates/actors/partials/monster-attributes-tab.html +++ b/src/templates/actors/partials/monster-attributes-tab.html @@ -10,11 +10,21 @@
  • -

    {{ localize "OSE.ArmorClassShort" }}

    + {{#if config.ascendingAC}} +

    + {{ localize "OSE.AscArmorClassShort" }}

    -
    + {{else}} +

    + {{ localize "OSE.ArmorClassShort" }}

    +
    + +
    + {{/if}}
  • {{ localize "OSE.Thac0" }}

    @@ -24,7 +34,8 @@
  • -

    {{ localize "OSE.AttacksShort" }}

    +

    {{ localize "OSE.AttacksShort" }} +

    @@ -32,15 +43,17 @@
  • {{#if data.retainer.enabled}}
  • -

    {{ localize "OSE.LoyaltyShort" }}

    +

    {{ localize "OSE.LoyaltyShort" }} +

    - +
  • {{/if}}
  • -

    {{ localize "OSE.MovementShort" }}

    +

    {{ localize "OSE.MovementShort" }} +

    @@ -54,7 +67,8 @@

    {{localize 'OSE.panel.abilities'}}

    {{#if owner}} - + {{/if}}
    @@ -89,7 +103,8 @@

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

    {{#if owner}} - + {{/if}}
    @@ -122,33 +137,39 @@ From dad790090eae27bf7cacf553030097065d4cb8e2 Mon Sep 17 00:00:00 2001 From: U~man Date: Thu, 2 Jul 2020 12:10:14 +0200 Subject: [PATCH 07/19] ENH: Inventory --- src/lang/en.json | 36 ++-- src/module/actor/actor-sheet.js | 183 ++++++++++-------- src/module/actor/character-sheet.js | 77 ++++---- src/module/actor/monster-sheet.js | 27 --- src/module/preloadTemplates.js | 1 + src/module/settings.js | 2 +- src/scss/actor-base.scss | 52 +---- src/scss/character.scss | 112 ++++++++++- src/scss/monster.scss | 64 +++++- src/template.json | 6 +- src/templates/actors/character-sheet.html | 6 + .../partials/character-abilities-tab.html | 46 +++++ .../partials/character-attributes-tab.html | 36 ---- .../partials/character-inventory-tab.html | 162 +++++++++++++--- 14 files changed, 529 insertions(+), 281 deletions(-) create mode 100644 src/templates/actors/partials/character-abilities-tab.html diff --git a/src/lang/en.json b/src/lang/en.json index a18a895..a4b1af9 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -75,6 +75,7 @@ "OSE.category.attributes": "Attributes", "OSE.category.inventory": "Inventory", + "OSE.category.abilities": "Abilities", "OSE.category.spells": "Spells", "OSE.category.notes": "Notes", @@ -92,18 +93,25 @@ "OSE.Setting.VariableWeaponDamage": "Variable Weapon Damage", "OSE.Setting.VariableWeaponDamageHint": "Weapons have different damage dice", - "OSE.ItemWeight": "Weight", - "OSE.ItemCost": "Cost", - "OSE.ItemQuantity": "Quantity", - "OSE.ItemRoll": "Roll", - "OSE.WeaponDamage": "Damage", - "OSE.WeaponMelee": "Melee", - "OSE.WeaponMissile": "Missile", - "OSE.WeaponSlow": "Slow", - "OSE.SpellRange": "Range", - "OSE.SpellClass": "Class", - "OSE.SpellDuration": "Duration", - "OSE.SpellLevel": "Level", - "OSE.ArmorAC": "AC", - "OSE.ArmorAAC": "AAC" + "OSE.items.Equip": "Equip", + "OSE.items.Unequip": "Unequip", + "OSE.items.Misc": "Misc", + "OSE.items.Weapons": "Weapons", + "OSE.items.Armors": "Armors", + "OSE.items.Weight": "Wght.", + "OSE.items.Qualities": "Qualities", + "OSE.items.Notes": "Notes", + "OSE.items.Cost": "Cost", + "OSE.items.Quantity": "Qt.", + "OSE.items.Roll": "Roll", + "OSE.items.Damage": "Damage", + "OSE.items.Melee": "Melee", + "OSE.items.Missile": "Missile", + "OSE.items.Slow": "Slow", + "OSE.spells.Range": "Range", + "OSE.spells.Class": "Class", + "OSE.spells.Duration": "Duration", + "OSE.spells.Level": "Level", + "OSE.items.ArmorAC": "AC", + "OSE.items.ArmorAAC": "AAC" } \ No newline at end of file diff --git a/src/module/actor/actor-sheet.js b/src/module/actor/actor-sheet.js index f05273f..aaad751 100644 --- a/src/module/actor/actor-sheet.js +++ b/src/module/actor/actor-sheet.js @@ -2,87 +2,116 @@ import { OseActor } from "./entity.js"; import { OseEntityTweaks } from "../dialog/entity-tweaks.js"; export class OseActorSheet extends ActorSheet { - constructor(...args) { - super(...args); - } - /* -------------------------------------------- */ - - getData() { - const data = super.getData(); + constructor(...args) { + super(...args); + } + /* -------------------------------------------- */ - data.config = CONFIG.OSE; - // Settings - data.config.ascendingAC = game.settings.get('ose', 'ascendingAC'); - - return data; - } + getData() { + const data = super.getData(); - activateListeners(html) { - html.find('.saving-throw .attribute-name a').click(ev => { - let actorObject = this.actor; - let element = event.currentTarget; - let save = element.parentElement.parentElement.dataset.save; - actorObject.rollSave(save, { event: event }); - }) + data.config = CONFIG.OSE; + // Settings + data.config.ascendingAC = game.settings.get("ose", "ascendingAC"); - super.activateListeners(html); - } + // Prepare owned items + this._prepareItems(data); - // Override to set resizable initial size - async _renderInner(...args) { - const html = await super._renderInner(...args); - this.form = html[0]; - - // Resize resizable classes - let resizable = html.find('.resizable'); - if (resizable.length == 0) { - return; - } - resizable.each((_, el) => { - let heightDelta = this.position.height - (this.options.height); - el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; - }); - return html; - } - - async _onResize(event) { - super._onResize(event); - let html = $(event.path); - let resizable = html.find('.resizable'); - resizable.each((_, el) => { - let heightDelta = this.position.height - (this.options.height); - el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; - }); - } + return data; + } - - _onConfigureActor(event) { - event.preventDefault(); - new OseEntityTweaks(this.actor, { - top: this.position.top + 40, - left: this.position.left + (this.position.width - 400) / 2, - }).render(true); - } + /** + * Organize and classify Owned Items for Character sheets + * @private + */ + _prepareItems(data) { + // Partition items by category + let [inventory, weapons, armors, abilities, spells] = data.items.reduce( + (arr, item) => { + // Classify items into types + if (item.type === "item") arr[0].push(item); + else if (item.type === "weapon") arr[1].push(item); + else if (item.type === "armor") arr[2].push(item); + else if (item.type === "ability") arr[3].push(item); + else if (item.type === "spell") arr[4].push(item); + return arr; + }, + [[], [], [], [], []] + ); - /** - * Extend and override the sheet header buttons - * @override - */ - _getHeaderButtons() { - let buttons = super._getHeaderButtons(); - - // Token Configuration - const canConfigure = game.user.isGM || this.actor.owner; - if (this.options.editable && canConfigure) { - buttons = [ - { - label: 'Tweaks', - class: 'configure-actor', - icon: 'fas fa-dice', - onclick: (ev) => this._onConfigureActor(ev), - }, - ].concat(buttons); - } - return buttons; + // Assign and return + data.inventory = inventory; + data.weapons = weapons; + data.armors = armors; + data.spells = spells; + data.abilities = abilities; + } + + activateListeners(html) { + html.find(".saving-throw .attribute-name a").click((ev) => { + let actorObject = this.actor; + let element = event.currentTarget; + let save = element.parentElement.parentElement.dataset.save; + actorObject.rollSave(save, { event: event }); + }); + + super.activateListeners(html); + } + + // Override to set resizable initial size + async _renderInner(...args) { + const html = await super._renderInner(...args); + this.form = html[0]; + + // Resize resizable classes + let resizable = html.find(".resizable"); + if (resizable.length == 0) { + return; } -} \ No newline at end of file + resizable.each((_, el) => { + let heightDelta = this.position.height - this.options.height; + el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; + }); + return html; + } + + async _onResize(event) { + super._onResize(event); + let html = $(event.path); + let resizable = html.find(".resizable"); + resizable.each((_, el) => { + let heightDelta = this.position.height - this.options.height; + el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; + }); + } + + _onConfigureActor(event) { + event.preventDefault(); + new OseEntityTweaks(this.actor, { + top: this.position.top + 40, + left: this.position.left + (this.position.width - 400) / 2, + }).render(true); + } + + /** + * Extend and override the sheet header buttons + * @override + */ + _getHeaderButtons() { + let buttons = super._getHeaderButtons(); + + // Token Configuration + const canConfigure = game.user.isGM || this.actor.owner; + if (this.options.editable && canConfigure) { + buttons = [ + { + label: "Tweaks", + class: "configure-actor", + icon: "fas fa-dice", + onclick: (ev) => this._onConfigureActor(ev), + }, + ].concat(buttons); + } + return buttons; + } +} diff --git a/src/module/actor/character-sheet.js b/src/module/actor/character-sheet.js index 144e430..fe569fd 100644 --- a/src/module/actor/character-sheet.js +++ b/src/module/actor/character-sheet.js @@ -42,57 +42,44 @@ export class OseActorSheetCharacter extends OseActorSheet { for (let [a, score] of Object.entries(data.data.scores)) { data.data.scores[a].label = game.i18n.localize(`OSE.scores.${a}`); } - // Prepare owned items - this._prepareItems(data); // Settings - data.config.individualInit = game.settings.get('ose', 'individualInit'); + data.config.variableWeaponDamage = game.settings.get( + "ose", + "variableWeaponDamage" + ); + data.config.ascendingAC = game.settings.get("ose", "ascendingAC"); + data.config.individualInit = game.settings.get("ose", "individualInit"); return data; } - /** - * Organize and classify Owned Items for Character sheets - * @private - */ - _prepareItems(data) { - // Partition items by category - let [inventory, abilities, spells] = data.items.reduce( - (arr, item) => { - // Classify items into types - if (item.type === "item") arr[0].push(item); - if (item.type === "ability") arr[1].push(item); - else if (item.type === "spell") arr[2].push(item); - return arr; - }, - [[], [], [], []] - ); - - // Assign and return - data.inventory = inventory; - data.spells = spells; - data.abilities = abilities; - } - /* -------------------------------------------- */ _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); + 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"); + 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()); + 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; + const item = this.actor.getOwnedItem(itemId); + return item.update({ "data.quantity.value": parseInt(event.target.value) }); + } + /** * Activate event listeners using the prepared sheet HTML * @param html {HTML} The prepared HTML object ready to be rendered into the DOM @@ -128,16 +115,34 @@ export class OseActorSheetCharacter extends OseActorSheet { return this.actor.createOwnedItem(itemData); }); - // Item summaries - html.find('.item .item-name h4').click(event => this._onItemSummary(event)); + //Toggle Equipment + html.find(".item-toggle").click(async (ev) => { + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.getOwnedItem(li.data("itemId")); + await this.actor.updateOwnedItem({ + _id: li.data("itemId"), + data: { + equipped: !item.data.data.equipped, + }, + }); + }); - - html.find('.ability-score .attribute-name a').click(ev => { + html + .find(".quantity input") + .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; let score = element.parentElement.parentElement.dataset.score; actorObject.rollCheck(score, { event: event }); - }) + }); // Handle default listeners last so system listeners are triggered first super.activateListeners(html); diff --git a/src/module/actor/monster-sheet.js b/src/module/actor/monster-sheet.js index e0820ff..e799ed2 100644 --- a/src/module/actor/monster-sheet.js +++ b/src/module/actor/monster-sheet.js @@ -39,39 +39,12 @@ export class OseActorSheetMonster extends OseActorSheet { getData() { const data = super.getData(); - // Prepare owned items - this._prepareItems(data); - // Settings data.config.morale = game.settings.get('ose', 'morale'); return data; } - /** - * Organize and classify Owned Items for Character sheets - * @private - */ - _prepareItems(data) { - // Partition items by category - let [inventory, abilities, spells] = data.items.reduce( - (arr, item) => { - // Classify items into types - if (item.type === "item") arr[0].push(item); - if (item.type === "ability") arr[1].push(item); - else if (item.type === "spell") arr[2].push(item); - return arr; - }, - [[], [], [], []] - ); - - // Assign and return - data.inventory = inventory; - data.spells = spells; - data.abilities = abilities; - } - - _onItemSummary(event) { event.preventDefault(); let li = $(event.currentTarget).parents(".item"), diff --git a/src/module/preloadTemplates.js b/src/module/preloadTemplates.js index 9bbff1c..4b4c546 100644 --- a/src/module/preloadTemplates.js +++ b/src/module/preloadTemplates.js @@ -7,6 +7,7 @@ export const preloadHandlebarsTemplates = async function () { //Sheet tabs 'systems/ose/templates/actors/partials/character-header.html', 'systems/ose/templates/actors/partials/character-attributes-tab.html', + 'systems/ose/templates/actors/partials/character-abilities-tab.html', 'systems/ose/templates/actors/partials/character-spells-tab.html', 'systems/ose/templates/actors/partials/character-inventory-tab.html', diff --git a/src/module/settings.js b/src/module/settings.js index 00f2f46..4a01fcc 100644 --- a/src/module/settings.js +++ b/src/module/settings.js @@ -35,7 +35,7 @@ export const registerSettings = function () { config: true }); - game.settings.register('ose', 'variableDamage', { + game.settings.register('ose', 'variableWeaponDamage', { name: game.i18n.localize('OSE.Setting.VariableWeaponDamage'), hint: game.i18n.localize('OSE.Setting.VariableWeaponDamageHint'), default: false, diff --git a/src/scss/actor-base.scss b/src/scss/actor-base.scss index 3009bfe..b085386 100644 --- a/src/scss/actor-base.scss +++ b/src/scss/actor-base.scss @@ -129,57 +129,7 @@ } .editor { height: 300px; - } - .inventory { - .item-entry { - padding: 0; - margin: 0; - list-style: none; - .item { - .item-image { - flex: 0 0 24px; - height: 24px; - background-size: cover; - } - .item-name { - line-height: 24px; - height: 24px; - 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: 24px; - flex: 0 0 32px; - margin: 0 3px; - .fas { - color: $colorTan; - font-size: 12px; - &:hover { - color: $colorDark; - } - } - } - } - .item-summary { - font-size: 12px; - padding: 0 4px; - } - &:nth-child(odd) { - background: rgba(0, 0, 0, 0.1); - } - } + padding: 4px; } } } diff --git a/src/scss/character.scss b/src/scss/character.scss index bdb073b..d71dbad 100644 --- a/src/scss/character.scss +++ b/src/scss/character.scss @@ -18,13 +18,111 @@ /* Sheet Body */ /* ----------------------------------------- */ .sheet-body { - } - - - .abilities { - .panel-content { - height: 250px; - overflow: auto; + .inventory { + overflow: auto; + height: 520px; + .items-section { + .header-field { + margin: 0; + } + } + .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; + } + .item-list { + list-style: none; + margin: 0; + padding: 0; + li { + padding: 0 2px; + } + .item-header { + @extend %header-field !optional; + padding: 0px; + margin-bottom: 0px; + } + .item-entry { + &:nth-child(even) { + 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; + .item-image { + flex-basis: 30px; + flex-grow: 0; + background-size: contain; + background-repeat: no-repeat; + &:hover { + background-image: url("/icons/svg/d20-grey.svg") !important; + cursor: pointer; + } + } + 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 { + margin: 4px 0; + display: flex; + input { + 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); + } + } } } diff --git a/src/scss/monster.scss b/src/scss/monster.scss index 96cb216..5654c8d 100644 --- a/src/scss/monster.scss +++ b/src/scss/monster.scss @@ -1,6 +1,6 @@ .ose.actor.monster { - min-height: 565px; - min-width: 460px; + min-height: 565px; + min-width: 460px; .sheet-body { .editor { height: 300px; @@ -9,13 +9,65 @@ .abilities { .panel-content { height: 230px; - overflow: auto; + overflow: auto; } } .attribute-row { - padding: 2px; - .abilities { - margin: 2px; + 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 2dab957..4d8ec4c 100644 --- a/src/template.json +++ b/src/template.json @@ -13,10 +13,12 @@ "max": 20 }, "ac": { + "naked": 0, "value": 0, "mod": 0 }, "aac": { + "naked": 0, "value": 0, "mod": 0 }, @@ -141,7 +143,7 @@ "max": 0 }, "cost": 0, - "weight": 0 + "weight": 80 }, "weapon": { "description": "", @@ -151,6 +153,7 @@ "missile": true, "ranged": true, "cost": 0, + "equipped": false, "weight": 0 }, "armor": { @@ -158,6 +161,7 @@ "ac": 9, "aac": 10, "cost": 0, + "equipped": false, "weight": 0 }, "spell": { diff --git a/src/templates/actors/character-sheet.html b/src/templates/actors/character-sheet.html index 1d2ede3..4fa3b7f 100644 --- a/src/templates/actors/character-sheet.html +++ b/src/templates/actors/character-sheet.html @@ -12,6 +12,9 @@ {{localize "OSE.category.inventory"}} + + {{localize "OSE.category.abilities"}} + {{#if data.spells.enabled}} {{localize "OSE.category.spells"}} @@ -30,6 +33,9 @@
    {{> "systems/ose/templates/actors/partials/character-inventory-tab.html"}}
    +
    + {{> "systems/ose/templates/actors/partials/character-abilities-tab.html"}} +
    {{#if data.spells.enabled}}
    {{> "systems/ose/templates/actors/partials/character-spells-tab.html"}} diff --git a/src/templates/actors/partials/character-abilities-tab.html b/src/templates/actors/partials/character-abilities-tab.html new file mode 100644 index 0000000..a16022e --- /dev/null +++ b/src/templates/actors/partials/character-abilities-tab.html @@ -0,0 +1,46 @@ +
    + +
      +
      + {{#each abilities as |item|}} +
    • +
      +
      +
      +

      + {{item.name~}} +

      +
      +
      + {{#if ../owner}} + + + {{/if}} +
      +
      +
    • + {{/each}} +
      +
    +
    diff --git a/src/templates/actors/partials/character-attributes-tab.html b/src/templates/actors/partials/character-attributes-tab.html index 540842b..b802c76 100644 --- a/src/templates/actors/partials/character-attributes-tab.html +++ b/src/templates/actors/partials/character-attributes-tab.html @@ -111,42 +111,6 @@
  • - {{!-- Skills and abilities --}} -
    -
    -

    {{localize 'OSE.panel.abilities'}}

    -
    - {{#if owner}} - - {{/if}} -
    -
    -
      -
      - {{#each abilities as |item|}} -
    • -
      -
      -
      -

      - {{item.name~}} -

      -
      -
      - {{#if ../owner}} - - - {{/if}} -
      -
      -
    • - {{/each}} -
      -
    -
    {{!-- Saving throws --}}
      diff --git a/src/templates/actors/partials/character-inventory-tab.html b/src/templates/actors/partials/character-inventory-tab.html index b370525..9c09493 100644 --- a/src/templates/actors/partials/character-inventory-tab.html +++ b/src/templates/actors/partials/character-inventory-tab.html @@ -1,29 +1,141 @@
      -
      - {{#each inventory as |item|}} -
    • -
      -
      -
      -

      - {{item.name~}} -

      -
      -
      - {{#if ../owner}} - - - {{/if}} -
      +
      +
    • +
      {{localize "OSE.items.Weapons"}}
      + {{#if config.variableWeaponDamage}} +
      {{localize "OSE.items.Damage"}}
      + {{/if}} +
      {{localize "OSE.items.Qualities"}}
      +
      {{localize "OSE.items.Weight"}}
      +
    • - {{/each}} +
        + {{#each weapons as |item|}} +
      1. +
        + + {{#if config.variableWeaponDamage}} +
        + {{item.data.damage}} +
        + {{/if}} +
        + {{item.data.qualities}} +
        +
        + {{item.data.weight}} +
        +
        + {{#if ../owner}} + + + + + + {{/if}} +
        +
        +
      2. + {{/each}} +
      -
      +
      +
    • +
      {{localize "OSE.items.Armors"}}
      + {{#if config.ascendingAC}} +
      {{localize "OSE.items.ArmorAAC"}}
      + {{else}} +
      {{localize "OSE.items.ArmorAC"}}
      + {{/if}} +
      {{localize "OSE.items.Weight"}}
      + +
    • +
        + {{#each armors as |item|}} +
      1. +
        + +
        + {{#if config.ascendingAC}} + {{item.data.aac}} + {{else}} + {{item.data.ac}} + {{/if}} +
        +
        + {{item.data.weight}} +
        +
        + {{#if ../owner}} + + + + + + {{/if}} +
        +
        +
      2. + {{/each}} +
      +
      +
      +
    • +
      {{localize "OSE.items.Misc"}}
      +
      {{localize "OSE.items.Quantity"}}
      +
      {{localize "OSE.items.Weight"}}
      + +
    • +
        + {{#each inventory as |item|}} +
      1. +
        + +
        + {{#if item.data.quantity.max}} / {{item.data.quantity.max}}{{/if}} +
        +
        + {{item.data.weight}} +
        +
        + {{#if ../owner}} + + + {{/if}} +
        +
        +
      2. + {{/each}} +
      +
      +
    \ No newline at end of file From e9f3dc2247ab12d28c5fa130c52f56628e687fa0 Mon Sep 17 00:00:00 2001 From: U~man Date: Thu, 2 Jul 2020 13:38:25 +0200 Subject: [PATCH 08/19] ENH: Item sheets styling --- src/lang/en.json | 5 +- src/scss/character.scss | 12 +-- src/scss/item.scss | 20 ++++- src/templates/actors/character-sheet.html | 12 +-- .../partials/character-inventory-tab.html | 4 +- .../actors/partials/character-spells-tab.html | 89 +++---------------- src/templates/items/armor-sheet.html | 8 +- src/templates/items/item-sheet.html | 37 ++++++-- src/templates/items/spell-sheet.html | 18 ++-- src/templates/items/weapon-sheet.html | 34 +++---- 10 files changed, 109 insertions(+), 130 deletions(-) diff --git a/src/lang/en.json b/src/lang/en.json index a4b1af9..0c48871 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -60,7 +60,8 @@ "OSE.ArmorClass": "Armor Class", "OSE.ArmorClassShort": "AC", "OSE.AscArmorClassShort": "AAC", - "OSE.SpellDC": "DC", + "OSE.SpellDC": "Spell DC", + "OSE.SpellDCShort": "DC", "OSE.Thac0": "THAC0", "OSE.MeleeShort": "MEL", "OSE.Melee": "Melee", @@ -98,7 +99,7 @@ "OSE.items.Misc": "Misc", "OSE.items.Weapons": "Weapons", "OSE.items.Armors": "Armors", - "OSE.items.Weight": "Wght.", + "OSE.items.Weight": "Wgt.", "OSE.items.Qualities": "Qualities", "OSE.items.Notes": "Notes", "OSE.items.Cost": "Cost", diff --git a/src/scss/character.scss b/src/scss/character.scss index d71dbad..84e0103 100644 --- a/src/scss/character.scss +++ b/src/scss/character.scss @@ -55,6 +55,12 @@ &:nth-child(even) { background: rgba(0, 0, 0, 0.1); } + &:hover { + .item-image { + background-image: url("/icons/svg/d20-grey.svg") !important; + cursor: pointer; + } + } } .item { line-height: 30px; @@ -77,10 +83,6 @@ flex-grow: 0; background-size: contain; background-repeat: no-repeat; - &:hover { - background-image: url("/icons/svg/d20-grey.svg") !important; - cursor: pointer; - } } h4 { margin: 0; @@ -106,9 +108,9 @@ flex-grow: 0; text-align: center; &.quantity { - margin: 4px 0; display: flex; input { + margin: 3px 0; border-bottom: none; } } diff --git a/src/scss/item.scss b/src/scss/item.scss index 3639051..0ef93c2 100644 --- a/src/scss/item.scss +++ b/src/scss/item.scss @@ -4,8 +4,26 @@ } .sheet-body { .stats { - flex: 0 0 70px; + flex: 0 0 90px; border-right: 1px groove rgba(0, 0, 0, 0.2); + padding-right: 2px; + .form-group { + margin: 2px; + border: 1px solid rgba(0, 0, 0, 0.15); + label { + background: rgba(0, 0, 0, 0.1); + padding: 0 4px; + } + input { + border-bottom: none; + margin: auto 0; + } + } + .block-input { + display: flex; + flex-direction: column; + text-align: center; + } } .editor { height: 255px; diff --git a/src/templates/actors/character-sheet.html b/src/templates/actors/character-sheet.html index 4fa3b7f..30b6431 100644 --- a/src/templates/actors/character-sheet.html +++ b/src/templates/actors/character-sheet.html @@ -9,9 +9,6 @@ {{localize "OSE.category.attributes"}} - - {{localize "OSE.category.inventory"}} - {{localize "OSE.category.abilities"}} @@ -20,6 +17,9 @@ {{localize "OSE.category.spells"}} {{/if}} + + {{localize "OSE.category.inventory"}} + {{localize "OSE.category.notes"}} @@ -30,9 +30,6 @@
    {{> "systems/ose/templates/actors/partials/character-attributes-tab.html"}}
    -
    - {{> "systems/ose/templates/actors/partials/character-inventory-tab.html"}} -
    {{> "systems/ose/templates/actors/partials/character-abilities-tab.html"}}
    @@ -41,6 +38,9 @@ {{> "systems/ose/templates/actors/partials/character-spells-tab.html"}} {{/if}} +
    + {{> "systems/ose/templates/actors/partials/character-inventory-tab.html"}} +
    {{editor content=data.details.biography target="data.details.biography" button=true owner=owner editable=editable}} diff --git a/src/templates/actors/partials/character-inventory-tab.html b/src/templates/actors/partials/character-inventory-tab.html index 9c09493..01605c4 100644 --- a/src/templates/actors/partials/character-inventory-tab.html +++ b/src/templates/actors/partials/character-inventory-tab.html @@ -28,7 +28,7 @@ {{item.data.damage}}
    {{/if}} -
    +
    {{item.data.qualities}}
    @@ -122,7 +122,7 @@
    {{#if item.data.quantity.max}} / {{item.data.quantity.max}}{{/if}} + placeholder="0" />{{#if item.data.quantity.max}}/{{item.data.quantity.max}}{{/if}}
    {{item.data.weight}} diff --git a/src/templates/actors/partials/character-spells-tab.html b/src/templates/actors/partials/character-spells-tab.html index 4534787..210c6d4 100644 --- a/src/templates/actors/partials/character-spells-tab.html +++ b/src/templates/actors/partials/character-spells-tab.html @@ -1,102 +1,41 @@
    • -

      {{localize 'OSE.SpellDC'}}

      -
      - -
      +

      {{localize 'OSE.SpellDCShort'}}

      +
      + +
    • -
    • -

      {{localize 'OSE.Level'}} 1

      -
      - - / - -
      -
    • -
    • -

      {{localize 'OSE.Level'}} 2

      -
      - - / - -
      -
    • -
    • -

      {{localize 'OSE.Level'}} 3

      -
      - - / - -
      -
    • -
    • -

      {{localize 'OSE.Level'}} 4

      -
      - - / - -
      -
    • -
    • -

      {{localize 'OSE.Level'}} 5

      -
      - - / - -
      -
    • -
    • -

      {{localize 'OSE.Level'}} 6

      -
      - - / - -
      -

    {{localize 'OSE.category.spells'}}

    -
    - {{#if owner}} - - {{/if}} -
    +
    + {{#if owner}} + + {{/if}} +
    {{#each spells as |item|}}
  • -
    +

    {{item.name~}}

    {{#if ../owner}} - - + + {{/if}}
  • {{/each}}
    -
    + \ No newline at end of file diff --git a/src/templates/items/armor-sheet.html b/src/templates/items/armor-sheet.html index 23874f9..b6db292 100644 --- a/src/templates/items/armor-sheet.html +++ b/src/templates/items/armor-sheet.html @@ -11,25 +11,25 @@
    - +
    - +
    - +
    - +
    diff --git a/src/templates/items/item-sheet.html b/src/templates/items/item-sheet.html index 2704d00..3aaaed9 100644 --- a/src/templates/items/item-sheet.html +++ b/src/templates/items/item-sheet.html @@ -3,17 +3,36 @@

    - +

    - {{editor content=data.description target="data.description" - button=true owner=owner editable=editable}} +
    +
    +
    + +
    + / +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + {{editor content=data.description target="data.description" button=true + owner=owner editable=editable}} +
    +
    - + \ No newline at end of file diff --git a/src/templates/items/spell-sheet.html b/src/templates/items/spell-sheet.html index ce4e1d0..fde4184 100644 --- a/src/templates/items/spell-sheet.html +++ b/src/templates/items/spell-sheet.html @@ -11,31 +11,31 @@
    - +
    -
    - +
    +
    -
    - +
    +
    -
    - +
    +
    -
    - +
    +
    diff --git a/src/templates/items/weapon-sheet.html b/src/templates/items/weapon-sheet.html index c4fe94f..2d0dd08 100644 --- a/src/templates/items/weapon-sheet.html +++ b/src/templates/items/weapon-sheet.html @@ -13,42 +13,42 @@
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - +
    +
    - +
    - +
    - +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    {{editor content=data.description target="data.description" button=true From 65ab877386a9f873942f6e34e4788b51a2364747 Mon Sep 17 00:00:00 2001 From: U~man Date: Thu, 2 Jul 2020 16:18:19 +0200 Subject: [PATCH 09/19] ENH: Spells --- src/lang/en.json | 4 ++ src/module/actor/actor-sheet.js | 32 +++++++++- src/scss/actor-base.scss | 3 - src/scss/character.scss | 37 +++++++---- src/template.json | 16 ++--- .../partials/character-inventory-tab.html | 6 +- .../actors/partials/character-spells-tab.html | 63 +++++++++++-------- src/templates/items/spell-sheet.html | 2 +- 8 files changed, 109 insertions(+), 54 deletions(-) diff --git a/src/lang/en.json b/src/lang/en.json index 0c48871..a48e864 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -109,7 +109,11 @@ "OSE.items.Melee": "Melee", "OSE.items.Missile": "Missile", "OSE.items.Slow": "Slow", + + "OSE.spells.Memorized": "Memorized", + "OSE.spells.Cast": "Cast", "OSE.spells.Range": "Range", + "OSE.spells.Slots": "Slots", "OSE.spells.Class": "Class", "OSE.spells.Duration": "Duration", "OSE.spells.Level": "Level", diff --git a/src/module/actor/actor-sheet.js b/src/module/actor/actor-sheet.js index aaad751..a1417e5 100644 --- a/src/module/actor/actor-sheet.js +++ b/src/module/actor/actor-sheet.js @@ -39,11 +39,18 @@ 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 + if (!sortedSpells[lvl]) sortedSpells[lvl] = []; + sortedSpells[lvl].push(spells[i]); + } // Assign and return data.inventory = inventory; data.weapons = weapons; data.armors = armors; - data.spells = spells; + data.spells = sortedSpells; data.abilities = abilities; } @@ -55,6 +62,29 @@ export class OseActorSheet extends ActorSheet { actorObject.rollSave(save, { event: event }); }); + //Toggle Spells + html.find(".item-cast").click(async (ev) => { + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.getOwnedItem(li.data("itemId")); + await this.actor.updateOwnedItem({ + _id: li.data("itemId"), + data: { + cast: !item.data.data.cast, + }, + }); + }); + //Toggle Equipment + html.find(".item-memorize").click(async (ev) => { + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.getOwnedItem(li.data("itemId")); + await this.actor.updateOwnedItem({ + _id: li.data("itemId"), + data: { + memorized: !item.data.data.memorized, + }, + }); + }); + super.activateListeners(html); } diff --git a/src/scss/actor-base.scss b/src/scss/actor-base.scss index b085386..189ded6 100644 --- a/src/scss/actor-base.scss +++ b/src/scss/actor-base.scss @@ -10,9 +10,6 @@ .panel { border: 1px solid $colorDark; - &.spells { - border: 0; - } .panel-title { color: whitesmoke; background: $colorDark; diff --git a/src/scss/character.scss b/src/scss/character.scss index 84e0103..f32a585 100644 --- a/src/scss/character.scss +++ b/src/scss/character.scss @@ -21,10 +21,8 @@ .inventory { overflow: auto; height: 520px; - .items-section { - .header-field { - margin: 0; - } + .header-spells { + line-height: 30px; } .item-titles { text-align: center; @@ -38,13 +36,22 @@ font-size: 12px; background: $colorDark; color: white; + input { + color: white; + margin: auto; + } } .item-list { list-style: none; margin: 0; padding: 0; - li { - padding: 0 2px; + &>* { + line-height: 30px; + } + .item-summary { + font-size: 13px; + padding: 0 4px; + line-height: 20px; } .item-header { @extend %header-field !optional; @@ -55,12 +62,6 @@ &:nth-child(even) { background: rgba(0, 0, 0, 0.1); } - &:hover { - .item-image { - background-image: url("/icons/svg/d20-grey.svg") !important; - cursor: pointer; - } - } } .item { line-height: 30px; @@ -78,11 +79,18 @@ 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; @@ -125,6 +133,11 @@ color: rgba(0, 0, 0, 0.2); } } + &.spells { + .item-controls { + flex-basis: 30px; + } + } } } diff --git a/src/template.json b/src/template.json index 4d8ec4c..ee9c1e3 100644 --- a/src/template.json +++ b/src/template.json @@ -42,27 +42,27 @@ "spells": { "enabled": false, "dc": 0, - "lvl1": { + "1": { "value": 0, "max": 0 }, - "lvl2": { + "2": { "value": 0, "max": 0 }, - "lvl3": { + "3": { "value": 0, "max": 0 }, - "lvl4": { + "4": { "value": 0, "max": 0 }, - "lvl5": { + "5": { "value": 0, "max": 0 }, - "lvl6": { + "6": { "value": 0, "max": 0 } @@ -170,7 +170,9 @@ "duration": "", "range": "", "roll": "", - "description": "" + "description": "", + "memorized": false, + "cast": false }, "ability": { "requirements": "", diff --git a/src/templates/actors/partials/character-inventory-tab.html b/src/templates/actors/partials/character-inventory-tab.html index 01605c4..d3753da 100644 --- a/src/templates/actors/partials/character-inventory-tab.html +++ b/src/templates/actors/partials/character-inventory-tab.html @@ -8,7 +8,7 @@
    {{localize "OSE.items.Qualities"}}
    {{localize "OSE.items.Weight"}}
      @@ -59,7 +59,7 @@ {{/if}}
      {{localize "OSE.items.Weight"}}
        @@ -105,7 +105,7 @@
        {{localize "OSE.items.Quantity"}}
        {{localize "OSE.items.Weight"}}
          diff --git a/src/templates/actors/partials/character-spells-tab.html b/src/templates/actors/partials/character-spells-tab.html index 210c6d4..8c08890 100644 --- a/src/templates/actors/partials/character-spells-tab.html +++ b/src/templates/actors/partials/character-spells-tab.html @@ -1,41 +1,50 @@ -
          -
            -
          • -

            {{localize 'OSE.SpellDCShort'}}

            -
            - +
            +
            +
          • +
            +
            {{localize 'OSE.SpellDC'}}
            +
            +
          • +
            + {{#each spells as |spellGroup id|}} +
              +
            1. +
              {{localize "OSE.spells.Level"}} {{id}}
              +
              {{localize 'OSE.spells.Slots'}}
              +
              /
              +
              +
            2. -
          -
          -
          -
          -

          {{localize 'OSE.category.spells'}}

          -
          - {{#if owner}} - - {{/if}} -
          -
          -
          - {{#each spells as |item|}} + {{#each spellGroup as |item|}}
        1. +
          + + +
          -

          - {{item.name~}} -

          + +

          + {{item.name~}} +

          +
          - {{#if ../owner}} - - + {{#if ../../owner}} + + {{/if}}
        2. {{/each}} -
          +
        + {{/each}} \ No newline at end of file diff --git a/src/templates/items/spell-sheet.html b/src/templates/items/spell-sheet.html index fde4184..8634ca2 100644 --- a/src/templates/items/spell-sheet.html +++ b/src/templates/items/spell-sheet.html @@ -13,7 +13,7 @@
        - +
        From c8be217e7eb9b9c458b557da6b97683e116ae98d Mon Sep 17 00:00:00 2001 From: U~man Date: Thu, 2 Jul 2020 18:13:08 +0200 Subject: [PATCH 10/19] ENH: Abilities --- src/lang/en.json | 7 +- src/module/actor/character-sheet.js | 1 + src/module/actor/entity.js | 40 ++++++++++++ src/scss/actor-base.scss | 8 +++ src/scss/character.scss | 12 +++- src/scss/item.scss | 6 +- src/template.json | 7 +- .../actors/dialogs/tweaks-dialog.html | 13 ++++ .../partials/character-abilities-tab.html | 64 ++++++++----------- .../partials/character-attributes-tab.html | 13 ++++ .../actors/partials/character-header.html | 5 +- src/templates/items/ability-sheet.html | 18 +++++- 12 files changed, 145 insertions(+), 49 deletions(-) diff --git a/src/lang/en.json b/src/lang/en.json index a48e864..2a6f65d 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -16,6 +16,7 @@ "OSE.Alignment": "Alignment", "OSE.Level": "Level", "OSE.Experience": "Experience", + "OSE.ExperienceBonus": "Bonus Experience", "OSE.Treasure": "Treasure type", "OSE.Size": "Size", "OSE.Morale": "Morale", @@ -109,6 +110,8 @@ "OSE.items.Melee": "Melee", "OSE.items.Missile": "Missile", "OSE.items.Slow": "Slow", + "OSE.items.ArmorAC": "AC", + "OSE.items.ArmorAAC": "AAC", "OSE.spells.Memorized": "Memorized", "OSE.spells.Cast": "Cast", @@ -117,6 +120,6 @@ "OSE.spells.Class": "Class", "OSE.spells.Duration": "Duration", "OSE.spells.Level": "Level", - "OSE.items.ArmorAC": "AC", - "OSE.items.ArmorAAC": "AAC" + + "OSE.abilities.Requirements": "Requirements" } \ No newline at end of file diff --git a/src/module/actor/character-sheet.js b/src/module/actor/character-sheet.js index fe569fd..de05bab 100644 --- a/src/module/actor/character-sheet.js +++ b/src/module/actor/character-sheet.js @@ -51,6 +51,7 @@ export class OseActorSheetCharacter extends OseActorSheet { data.config.ascendingAC = game.settings.get("ose", "ascendingAC"); data.config.individualInit = game.settings.get("ose", "individualInit"); + data.mods = this.actor.computeModifiers(); return data; } diff --git a/src/module/actor/entity.js b/src/module/actor/entity.js index 5262f04..f3fd59f 100644 --- a/src/module/actor/entity.js +++ b/src/module/actor/entity.js @@ -41,4 +41,44 @@ export class OseActor extends Actor { title: `${label} ${game.i18n.localize('OSE.AbilityCheck')}`, }); } + + computeModifiers() { + let _valueToMod = (val) => { + switch (val) { + case 3: + return -3; + case 4: + case 5: + return -2; + case 6: + case 7: + case 8: + return -1; + case 9: + case 10: + case 11: + case 12: + return 0; + case 13: + case 14: + case 15: + return 1; + case 16: + case 17: + return 2; + case 18: + return 3; + default: + return 0; + } + }; + return { + str: _valueToMod(this.data.data.scores.str.value), + int: _valueToMod(this.data.data.scores.int.value), + dex: _valueToMod(this.data.data.scores.dex.value), + cha: _valueToMod(this.data.data.scores.cha.value), + wis: _valueToMod(this.data.data.scores.wis.value), + con: _valueToMod(this.data.data.scores.con.value), + } + } } diff --git a/src/scss/actor-base.scss b/src/scss/actor-base.scss index 189ded6..2ee8b45 100644 --- a/src/scss/actor-base.scss +++ b/src/scss/actor-base.scss @@ -95,6 +95,7 @@ margin: 0; padding: 0; .attribute { + position: relative; margin: 10px 2px; border: 1px solid $colorTan; .attribute-name { @@ -109,6 +110,13 @@ display: flex; flex-direction: row; } + .attribute-mod { + position: absolute; + color: $colorTan; + right: 5px; + top: 0; + font-size: 13px; + } } } .attribute-group { diff --git a/src/scss/character.scss b/src/scss/character.scss index f32a585..cab8782 100644 --- a/src/scss/character.scss +++ b/src/scss/character.scss @@ -12,6 +12,13 @@ /* ----------------------------------------- */ .sheet-header { + .xp-bonus { + top: -15px; + right: 3px; + color: $colorTan; + font-size: 10px; + position: absolute; + } } /* ----------------------------------------- */ @@ -20,7 +27,6 @@ .sheet-body { .inventory { overflow: auto; - height: 520px; .header-spells { line-height: 30px; } @@ -60,7 +66,9 @@ } .item-entry { &:nth-child(even) { - background: rgba(0, 0, 0, 0.1); + .item { + background: rgba(0, 0, 0, 0.1); + } } } .item { diff --git a/src/scss/item.scss b/src/scss/item.scss index 0ef93c2..9463920 100644 --- a/src/scss/item.scss +++ b/src/scss/item.scss @@ -1,6 +1,8 @@ .ose.sheet.item { .profile-img { border: none; + flex: 0 0 84px; + height: 84px; } .sheet-body { .stats { @@ -26,10 +28,10 @@ } } .editor { - height: 255px; + height: 240px; } .weapon-editor .editor { - height: 230px; + height: 215px; } } } \ No newline at end of file diff --git a/src/template.json b/src/template.json index ee9c1e3..a0ebbc9 100644 --- a/src/template.json +++ b/src/template.json @@ -78,8 +78,11 @@ "alignment": "", "literate": false, "level": 1, - "xp": 0, - "xpmod": 0 + "xp": { + "next": 0, + "value": 0, + "bonus": 0 + } }, "scores": { "str": { diff --git a/src/templates/actors/dialogs/tweaks-dialog.html b/src/templates/actors/dialogs/tweaks-dialog.html index 893a513..964c834 100644 --- a/src/templates/actors/dialogs/tweaks-dialog.html +++ b/src/templates/actors/dialogs/tweaks-dialog.html @@ -23,6 +23,19 @@ />
    + {{#if (eq this.type 'character')}} +
    + +
    + +
    +
    + {{/if}}
    diff --git a/src/templates/actors/partials/character-header.html b/src/templates/actors/partials/character-header.html index 67cf726..b3dc32b 100644 --- a/src/templates/actors/partials/character-header.html +++ b/src/templates/actors/partials/character-header.html @@ -27,9 +27,12 @@
  • - + {{#if data.details.xp.bonus}} + +{{data.details.xp.bonus}}% + {{/if}}
  • \ No newline at end of file diff --git a/src/templates/items/ability-sheet.html b/src/templates/items/ability-sheet.html index e2c2f77..b675edf 100644 --- a/src/templates/items/ability-sheet.html +++ b/src/templates/items/ability-sheet.html @@ -9,9 +9,21 @@
    - -
    -
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    {{editor content=data.description target="data.description" button=true owner=owner editable=editable}}
    From 2dfdfdf986ae501fbb2b90ddfddf74675bceb85e Mon Sep 17 00:00:00 2001 From: U~man Date: Thu, 2 Jul 2020 23:00:45 +0200 Subject: [PATCH 11/19] WIP: Counters --- src/assets/heart_empty.png | Bin 0 -> 8112 bytes src/assets/heart_full.png | Bin 0 -> 10726 bytes src/assets/shield.png | Bin 0 -> 7799 bytes src/lang/en.json | 1 + src/module/helpers.js | 18 ++++ src/ose.js | 17 +--- src/scss/actor-base.scss | 20 ++++- src/scss/character.scss | 39 +++++++++ src/scss/variables.scss | 2 +- .../partials/character-attributes-tab.html | 78 +++++++++--------- 10 files changed, 117 insertions(+), 58 deletions(-) create mode 100644 src/assets/heart_empty.png create mode 100644 src/assets/heart_full.png create mode 100644 src/assets/shield.png create mode 100644 src/module/helpers.js diff --git a/src/assets/heart_empty.png b/src/assets/heart_empty.png new file mode 100644 index 0000000000000000000000000000000000000000..06735457149e447e28c136c5955a7d21d4e34af2 GIT binary patch literal 8112 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
    $wNj7Jz>KtU>rPmVOE1d_1P^> z;67vvcovFLrhZk_@^}XsZU%R&ZqXFjqo3x-B_3AZ0@LJ>kEu^LdnvmVDjWJHOwlCB z1-)u~F^7ypb&sr8>5M|hLr8j06D^9NlYG?YXT4OcYLPc)jhSgC5POn%R{W=0dcd zM5f0{@w;+Lz@yof^`zPJELk?G?Ao*!`VyNBE3%kQcpoZPOe&KGV;M}yj+VAZQue4r zPu#qyhVXb(mZ&)XUQ+CNrTEvrGTf;FtpTZ#eH=5pHh0rLG^8XOl&+-o1ejs#y(h$3 z`hbns54pwplsO#y1hQe35y)3W)&7zAgll7(4s~))r2)12S|5zb;5vRrOuR0y5qt2+ z5|Ue2g!jVf%rPOu{jEk)fc`ks3>&N6{0&RFJ#a=&u;H7svdGo`e^Oy3Y!w^ltSaxD z%U6~SfQ8PBrkCclNIN)Ci{%NctJDjH+K7$k@<5|L4=TkH@lJNg&xH5{=+C)094qD8 zA@q4xW^ea!L(1!i^;s;viJi{CX-$jNyH%Bpnln9OJkWohW6)`Eq3yWX`5<$pW{{rU!zw z&&WA(Ci}TRkIS9~WgBWeevntf(IQ*^yqoY2EHP#c`PrcKi1mVnO@=#6z!kV9=r0Kt zwaasZpk7*y-O{#|Ql1f-I{p*A-uGbcjhu|2b8@>kDLy#>x za24@U#OlGi5iIIz6(2A#zVMy<%Z%Xqa6r6u*X^Lrh3EXjvjLld>xtG!Lyw>q5=X_U zACoCQcJmEwanQXGThn^LYW5inKcJ#q!-2k*^asZ#!;t&D`|HOPX*+EoT?DSdqt3M$ zq_Pb=^Csls%17#a_z^;+swFBGNfJVB9!3d}>lL;3KuH;VjGTAi8a;mNsn3o4U`%xO z{Bq#(+@VUvPpO@mb-9R7kA6u3*7Ks|FL?(Lt4wjJn0Yy!;F+xAW#MH+g{!3#BkpL+ zG2+uK(;5~0549wd)e9SMw~!vDw*FL?gQLf;Ii=p?A#mX>L&;pw;|d;)CZoNJ$D4tsbg~pYA;}F^=+9UwPM0N~6KE48 zZNibd6Q;Z1Kf{K0#&*JZ60#A79}5Aa9QYXB3_=iE?`an^;6Q*;#N>w>ot1JXJQ{Sa zCz<1c(I8X90|ltw8i=9`lnRL7mJKQ4m^J&M|8wrW@03~ex0RIcM*rw}d;+NiHH z=)hkh3UK387Ldm&z9T8u$9Gl*-fX)CQM+Dr2Pnbl*2yL7g~9D&)(SH)TQP{Ph-Z6N z41?^pL+VV1UE*0XfVFb#z*Ag-yA7>AR+pW2NQ-n37`)C8!njizhxGJ?NsjUxw!qmc zQc(z2o$>Wi$}h}D*Qxzl@L3ZvLrmMA(``_a)b=1R2LKiYt7rTF64wltXDosEEoJ{a So&Tla0b@gRgBm@z`2Pc)-wWpe literal 0 HcmV?d00001 diff --git a/src/assets/heart_full.png b/src/assets/heart_full.png new file mode 100644 index 0000000000000000000000000000000000000000..29747b88773073d63f503c2f298603d9df4c165a GIT binary patch literal 10726 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 OKut*tTJhZa&Hn+&t}=E2 literal 0 HcmV?d00001 diff --git a/src/assets/shield.png b/src/assets/shield.png new file mode 100644 index 0000000000000000000000000000000000000000..a2f7eed5bbed2ec1fb21b8ed44066078c8c90edc GIT binary patch literal 7799 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
    • -

      {{ localize "OSE.HitDiceShort" }}

      -
      - -
      -
    • -
    • -

      {{ localize "OSE.HealthShort" }} +

      {{ localize "OSE.HitDiceShort" }}

      -
      - - / - -
      -
    • -
    • - {{#if config.ascendingAC}} -

      - {{ localize "OSE.AscArmorClassShort" }}

      - +
      - {{else}} -

      - {{ localize "OSE.ArmorClassShort" }}

      -
      - -
      - {{/if}}
    • {{ localize "OSE.Thac0" }}

      @@ -62,7 +35,8 @@
    • {{/if}}
    • -

      {{ localize "OSE.MovementShort" }}

      +

      + {{ localize "OSE.MovementShort" }}

      @@ -80,7 +54,7 @@
      - {{mods.str}} + {{mods.str}}
    • @@ -88,7 +62,7 @@
      - {{mods.int}} + {{mods.int}}

    • @@ -96,7 +70,7 @@
      - {{mods.wis}} + {{mods.wis}}

    • @@ -104,7 +78,7 @@
      - {{mods.dex}} + {{mods.dex}}

    • @@ -112,7 +86,7 @@
      - {{mods.con}} + {{mods.con}}

    • @@ -120,44 +94,66 @@
      - {{mods.cha}} + {{mods.cha}}

    + {{!-- Resource Tracking --}} +
    +
    + + +
    +
    +
    +
    + {{#if config.ascendingAC}} + + + {{else}} + + + {{/if}} +
    +
    {{!-- Saving throws --}}
    • - {{ localize "OSE.saves.death.short" }}

      + {{ localize "OSE.saves.death.long" }}
    • - {{ localize "OSE.saves.wand.short" }}

      + {{ localize "OSE.saves.wand.long" }}
    • - {{ localize "OSE.saves.paralysis.short" }}

      + {{ localize "OSE.saves.paralysis.long" }}
    • - {{ localize "OSE.saves.breath.short" }}

      + {{ localize "OSE.saves.breath.long" }}
    • - {{ localize "OSE.saves.spell.short" }}

      + {{ localize "OSE.saves.spell.long" }}
      From 6141ae7693c4b2eea177c149218b55c99956fd8d Mon Sep 17 00:00:00 2001 From: U~man Date: Fri, 3 Jul 2020 14:37:49 +0200 Subject: [PATCH 12/19] ENH: Layout rework --- src/assets/heart_empty.png | Bin 8112 -> 4344 bytes src/assets/heart_full.png | Bin 10726 -> 10775 bytes src/assets/shield.png | Bin 7799 -> 4693 bytes src/lang/en.json | 10 +- src/module/actor/actor-sheet.js | 7 + src/module/helpers.js | 8 + src/module/item/entity.js | 75 ++++++++ src/scss/actor-base.scss | 24 ++- src/scss/apps.scss | 97 ++++++++++ src/scss/character.scss | 12 +- src/template.json | 8 +- .../actors/dialogs/tweaks-dialog.html | 22 +++ .../partials/character-attributes-tab.html | 176 +++++++++++------- src/templates/chat/item-card.html | 38 ++++ 14 files changed, 394 insertions(+), 83 deletions(-) create mode 100644 src/templates/chat/item-card.html diff --git a/src/assets/heart_empty.png b/src/assets/heart_empty.png index 06735457149e447e28c136c5955a7d21d4e34af2..99578eb28386bc9e4e1a4856d1c7ae1af93a6b09 100644 GIT binary patch delta 4289 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 literal 8112 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
      $wNj7Jz>KtU>rPmVOE1d_1P^> z;67vvcovFLrhZk_@^}XsZU%R&ZqXFjqo3x-B_3AZ0@LJ>kEu^LdnvmVDjWJHOwlCB z1-)u~F^7ypb&sr8>5M|hLr8j06D^9NlYG?YXT4OcYLPc)jhSgC5POn%R{W=0dcd zM5f0{@w;+Lz@yof^`zPJELk?G?Ao*!`VyNBE3%kQcpoZPOe&KGV;M}yj+VAZQue4r zPu#qyhVXb(mZ&)XUQ+CNrTEvrGTf;FtpTZ#eH=5pHh0rLG^8XOl&+-o1ejs#y(h$3 z`hbns54pwplsO#y1hQe35y)3W)&7zAgll7(4s~))r2)12S|5zb;5vRrOuR0y5qt2+ z5|Ue2g!jVf%rPOu{jEk)fc`ks3>&N6{0&RFJ#a=&u;H7svdGo`e^Oy3Y!w^ltSaxD z%U6~SfQ8PBrkCclNIN)Ci{%NctJDjH+K7$k@<5|L4=TkH@lJNg&xH5{=+C)094qD8 zA@q4xW^ea!L(1!i^;s;viJi{CX-$jNyH%Bpnln9OJkWohW6)`Eq3yWX`5<$pW{{rU!zw z&&WA(Ci}TRkIS9~WgBWeevntf(IQ*^yqoY2EHP#c`PrcKi1mVnO@=#6z!kV9=r0Kt zwaasZpk7*y-O{#|Ql1f-I{p*A-uGbcjhu|2b8@>kDLy#>x za24@U#OlGi5iIIz6(2A#zVMy<%Z%Xqa6r6u*X^Lrh3EXjvjLld>xtG!Lyw>q5=X_U zACoCQcJmEwanQXGThn^LYW5inKcJ#q!-2k*^asZ#!;t&D`|HOPX*+EoT?DSdqt3M$ zq_Pb=^Csls%17#a_z^;+swFBGNfJVB9!3d}>lL;3KuH;VjGTAi8a;mNsn3o4U`%xO z{Bq#(+@VUvPpO@mb-9R7kA6u3*7Ks|FL?(Lt4wjJn0Yy!;F+xAW#MH+g{!3#BkpL+ zG2+uK(;5~0549wd)e9SMw~!vDw*FL?gQLf;Ii=p?A#mX>L&;pw;|d;)CZoNJ$D4tsbg~pYA;}F^=+9UwPM0N~6KE48 zZNibd6Q;Z1Kf{K0#&*JZ60#A79}5Aa9QYXB3_=iE?`an^;6Q*;#N>w>ot1JXJQ{Sa zCz<1c(I8X90|ltw8i=9`lnRL7mJKQ4m^J&M|8wrW@03~ex0RIcM*rw}d;+NiHH z=)hkh3UK387Ldm&z9T8u$9Gl*-fX)CQM+Dr2Pnbl*2yL7g~9D&)(SH)TQP{Ph-Z6N z41?^pL+VV1UE*0XfVFb#z*Ag-yA7>AR+pW2NQ-n37`)C8!njizhxGJ?NsjUxw!qmc zQc(z2o$>Wi$}h}D*Qxzl@L3ZvLrmMA(``_a)b=1R2LKiYt7rTF64wltXDosEEoJ{a So&Tla0b@gRgBm@z`2Pc)-wWpe diff --git a/src/assets/heart_full.png b/src/assets/heart_full.png index 29747b88773073d63f503c2f298603d9df4c165a..ed2da98be5ed768af82caa8194891496f7e9f869 100644 GIT binary patch literal 10775 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 Jt7H}Ne*nMn@TmX* literal 10726 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 OKut*tTJhZa&Hn+&t}=E2 diff --git a/src/assets/shield.png b/src/assets/shield.png index a2f7eed5bbed2ec1fb21b8ed44066078c8c90edc..049f92a8b78a80e9e237e10e5dabeba65d86c67b 100644 GIT binary patch literal 4693 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 Qo1n8{ZfuRIH^kole+Dc!5&!@I diff --git a/src/lang/en.json b/src/lang/en.json index cd52679..fa0f5cd 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -57,8 +57,12 @@ "OSE.HealthShort": "HP", "OSE.HitDice": "Hit Dice", "OSE.HitDiceShort": "HD", - "OSE.Movement": "Movement", - "OSE.MovementShort": "MOV", + "OSE.Movement": "Movement Rate", + "OSE.MovementEncounter": "Encounter Movement Rate", + "OSE.MovementEncounterShort": "ENC", + "OSE.MovementOverland": "Overland Movement Rate", + "OSE.MovementOverlandShort": "OVE", + "OSE.MovementShort": "MR", "OSE.ArmorClass": "Armor Class", "OSE.ArmorClassShort": "AC", "OSE.AscArmorClassShort": "AAC", @@ -67,8 +71,10 @@ "OSE.Thac0": "THAC0", "OSE.MeleeShort": "MEL", "OSE.Melee": "Melee", + "OSE.MeleeBonus": "Melee Bonus", "OSE.MissileShort": "MIS", "OSE.Missile": "Missile", + "OSE.MissileBonus": "Missile Bonus", "OSE.Initiative": "Initiative", "OSE.InitiativeShort": "INIT", "OSE.Attacks": "Attacks Usable per Round", diff --git a/src/module/actor/actor-sheet.js b/src/module/actor/actor-sheet.js index a1417e5..d3790e9 100644 --- a/src/module/actor/actor-sheet.js +++ b/src/module/actor/actor-sheet.js @@ -85,6 +85,13 @@ export class OseActorSheet extends ActorSheet { }); }); + html.find(".item-image").click(async (ev) => { + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.getOwnedItem(li.data("itemId")); + item.roll(); + }); + + super.activateListeners(html); } diff --git a/src/module/helpers.js b/src/module/helpers.js index 0062abd..3613183 100644 --- a/src/module/helpers.js +++ b/src/module/helpers.js @@ -12,6 +12,14 @@ export const registerHelpers = async function () { return parseInt(rh) - parseInt(lh); }); + Handlebars.registerHelper("divide", function (lh, rh) { + return Math.floor(parseFloat(lh) / parseFloat(rh)); + }); + + Handlebars.registerHelper("mult", function (lh, rh) { + return parseInt(lh) * parseInt(rh); + }); + Handlebars.registerHelper("counter", function (status, value, max) { return status ? Math.clamped((100.0 * value) / max, 0, 100) : Math.clamped(100 - (100.0 * value) / max, 0, 100); }); diff --git a/src/module/item/entity.js b/src/module/item/entity.js index 0c23cc0..8c979a3 100644 --- a/src/module/item/entity.js +++ b/src/module/item/entity.js @@ -12,4 +12,79 @@ export class OseItem extends Item { prepareData() { super.prepareData(); } + + getChatData(htmlOptions) { + const data = duplicate(this.data.data); + + // Rich text description + data.description = TextEditor.enrichHTML(data.description, htmlOptions); + + // Item properties + const props = []; + const labels = this.labels; + + if (this.data.type == "weapon") { + props.push(data.qualities); + } + if (this.data.type == "spell") { + props.push( + `${data.class} ${data.lvl}`, + data.range, + data.duration + ); + } + if (data.hasOwnProperty("equipped")) { + props.push(data.equipped ? "Equipped" : "Not Equipped"); + } + + // Filter properties and return + data.properties = props.filter((p) => !!p); + return data; + } + + /** + * Roll the item to Chat, creating a chat card which contains follow up attack or damage roll options + * @return {Promise} + */ + async roll({ configureDialog = true } = {}) { + // Basic template rendering data + const token = this.actor.token; + const templateData = { + actor: this.actor, + tokenId: token ? `${token.scene._id}.${token.id}` : null, + item: this.data, + data: this.getChatData(), + labels: this.labels, + hasAttack: this.hasAttack, + isHealing: this.isHealing, + hasDamage: this.hasDamage, + isSpell: this.data.type === "spell", + hasSave: this.hasSave, + }; + + // Render the chat card template + const template = `systems/ose/templates/chat/item-card.html`; + const html = await renderTemplate(template, templateData); + + // Basic chat message data + const chatData = { + user: game.user._id, + type: CONST.CHAT_MESSAGE_TYPES.OTHER, + content: html, + speaker: { + actor: this.actor._id, + token: this.actor.token, + alias: this.actor.name, + }, + }; + + // Toggle default roll mode + let rollMode = game.settings.get("core", "rollMode"); + if (["gmroll", "blindroll"].includes(rollMode)) + chatData["whisper"] = ChatMessage.getWhisperRecipients("GM"); + if (rollMode === "blindroll") chatData["blind"] = true; + + // Create the chat message + return ChatMessage.create(chatData); + } } diff --git a/src/scss/actor-base.scss b/src/scss/actor-base.scss index 2099b9c..882d1e7 100644 --- a/src/scss/actor-base.scss +++ b/src/scss/actor-base.scss @@ -95,7 +95,7 @@ padding: 0; .attribute { position: relative; - margin: 10px; + margin: 8px; border: 1px solid $colorTan; .attribute-name { color: whitesmoke; @@ -104,25 +104,31 @@ background: $colorDark; text-align: center; } - .attribute-value { - padding: 4px; - display: flex; - flex-direction: row; - &.multiple input { - min-width: 28px; + &.attribute-secondaries { + margin: 10px 5px; + } + &.ability-score { + height: 40px; + .attribute-value { + line-height: 36px; } } + .attribute-value { + text-align: center; + padding: 4px; + } .attribute-mod { position: absolute; color: $colorTan; right: 5px; - top: 0; + top: -5px; font-size: 13px; } } } .attribute-group { flex: 0 0 105px; + margin: auto 0; .attributes { .attribute { display: flex; @@ -130,7 +136,7 @@ .attribute-name { width: 40px; margin: 0; - line-height: 28px; + line-height: 38px; a { margin: auto; } diff --git a/src/scss/apps.scss b/src/scss/apps.scss index e69de29..fcd39d7 100644 --- a/src/scss/apps.scss +++ b/src/scss/apps.scss @@ -0,0 +1,97 @@ + +.ose.chat-card { + font-style: normal; + font-size: 12px; + + .card-header { + padding: 3px 0; + border-top: 2px groove #FFF; + border-bottom: 2px groove #FFF; + + img { + flex: 0 0 36px; + margin-right: 5px; + } + + h3 { + flex: 1; + margin: 0; + line-height: 36px; + color: $colorOlive; + &:hover { + color: #111; + text-shadow: 0 0 10px red; + } + } + } + + .card-content { + margin: 5px 0; + + h3 { + font-size: 12px; + margin: 0; + font-weight: bold; + } + + > * { + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; + } + } + + .card-buttons { + margin: 5px 0; + + span { + display: block; + line-height: 28px; + text-align: center; + border: 1px solid $colorTan; + } + + button { + font-size: 12px; + height: 24px; + line-height: 20px; + margin: 2px 0; + } + } + + .card-footer { + padding: 3px 0 0; + border-top: 2px groove #FFF; + + span { + border-right: 2px groove #FFF; + padding: 0 5px 0 0; + font-size: 10px; + + &:last-child { + border-right: none; + padding-right: 0; + } + } + } + } + + .dice-roll .dice-total { + &.success { + color: inherit; + background: #c7d0c0; + border: 1px solid #006c00; + } + &.failure { + color: inherit; + background: #ffdddd; + border: 1px solid #6e0000; + } + &.critical { + color: green; + } + &.fumble { + color: red; + } + } \ No newline at end of file diff --git a/src/scss/character.scss b/src/scss/character.scss index 6576274..56f7748 100644 --- a/src/scss/character.scss +++ b/src/scss/character.scss @@ -28,10 +28,10 @@ .health { &.armor-class { background: url('/systems/ose/assets/shield.png') no-repeat center; - background-size: 90px; + background-size: 70px; } margin: 10px 0; - height: 90px; + height: 70px; position: relative; input { font-size: 16px; @@ -42,25 +42,25 @@ border-bottom: none; position: absolute; font-size: 24px; - top: 28px; + top: 10px; width: 70px; left: calc(50% - 35px); } .health-bottom { border-bottom: none; position: absolute; - bottom: 12px; + bottom: 8px; width: 40px; right: calc(50% + -20px); } .health-empty { background: url('/systems/ose/assets/heart_empty.png') no-repeat center; - background-size: 90px; + background-size: 70px; background-position: top; } .health-full { background: url('/systems/ose/assets/heart_full.png') no-repeat center; - background-size: 90px; + background-size: 70px; background-position: bottom; } } diff --git a/src/template.json b/src/template.json index a0ebbc9..84ae158 100644 --- a/src/template.json +++ b/src/template.json @@ -24,7 +24,10 @@ }, "thac0": { "value": 19, - "mod": 0 + "mod": { + "missile": 0, + "melee": 0 + } }, "saves": { "death": 10, @@ -34,8 +37,7 @@ "spell": 10 }, "movement": { - "base": 0, - "encounter": 0 + "base": 120 } }, "spellcaster": { diff --git a/src/templates/actors/dialogs/tweaks-dialog.html b/src/templates/actors/dialogs/tweaks-dialog.html index 964c834..42fff28 100644 --- a/src/templates/actors/dialogs/tweaks-dialog.html +++ b/src/templates/actors/dialogs/tweaks-dialog.html @@ -35,6 +35,28 @@ />
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    {{/if}}
    {{/if}} + + {{#if hasDamage}} + + {{/if}} + + {{#if hasSave}} + + {{/if}} + + {{#if data.formula}} + + {{/if}} +
    + +
    + {{#each data.properties}} + {{this}} + {{/each}} +
    +
    From 4f6c6e3c90294d5f8583ed71aee32cb089bd3640 Mon Sep 17 00:00:00 2001 From: U~man Date: Fri, 3 Jul 2020 15:30:40 +0200 Subject: [PATCH 13/19] ENH: Tabs --- src/scss/actor-base.scss | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/scss/actor-base.scss b/src/scss/actor-base.scss index 882d1e7..ef45fc7 100644 --- a/src/scss/actor-base.scss +++ b/src/scss/actor-base.scss @@ -74,21 +74,30 @@ } } .sheet-tabs { - color: whitesmoke; - background: $colorDark; - margin: 4px 0 0; - border: 1px solid $colorDark; + position: absolute; + transform: rotate(90deg); + top: 365px; + right: -166px; + width: 320px; + z-index: -1; .item { - padding: 2px; + padding: 0 10px; + margin-left: -5px; + text-indent: 4px; + background: url('/ui/parchment.jpg'); + border-top-right-radius: 4px; + border-top-left-radius: 15px; + box-shadow: 0 0 6px 1px $colorDark; + font-size: 13px; &.active { - background: $colorCrimson; + z-index: 1; + font-weight: bold; + text-shadow: none; } } } .sheet-body { padding: 5px 0; - border: 1px solid $colorDark; - border-top: none; height: calc(100% - 175px); .attributes { margin: 0; @@ -97,6 +106,7 @@ position: relative; margin: 8px; border: 1px solid $colorTan; + box-shadow: 0 0 2px $colorTan; .attribute-name { color: whitesmoke; padding: 2px; From 5afadf60398102717c181d6b2ea72cd3b1f2d50c Mon Sep 17 00:00:00 2001 From: U~man Date: Fri, 3 Jul 2020 16:04:31 +0200 Subject: [PATCH 14/19] FIX: Monsters and tabs --- src/module/actor/character-sheet.js | 2 +- src/scss/actor-base.scss | 11 ++++++----- src/scss/character.scss | 2 +- .../actors/partials/monster-attributes-tab.html | 12 ++++++------ 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/module/actor/character-sheet.js b/src/module/actor/character-sheet.js index de05bab..002606a 100644 --- a/src/module/actor/character-sheet.js +++ b/src/module/actor/character-sheet.js @@ -20,7 +20,7 @@ export class OseActorSheetCharacter extends OseActorSheet { classes: ["ose", "sheet", "actor", "character"], template: "systems/ose/templates/actors/character-sheet.html", width: 450, - height: 560, + height: 530, resizable: true, tabs: [ { diff --git a/src/scss/actor-base.scss b/src/scss/actor-base.scss index ef45fc7..600bef9 100644 --- a/src/scss/actor-base.scss +++ b/src/scss/actor-base.scss @@ -77,28 +77,29 @@ position: absolute; transform: rotate(90deg); top: 365px; - right: -166px; + right: -169px; width: 320px; z-index: -1; .item { - padding: 0 10px; + padding: 2px 10px 0; margin-left: -5px; text-indent: 4px; background: url('/ui/parchment.jpg'); border-top-right-radius: 4px; - border-top-left-radius: 15px; + border-top-left-radius: 80px; box-shadow: 0 0 6px 1px $colorDark; - font-size: 13px; + font-size: 12px; &.active { z-index: 1; font-weight: bold; text-shadow: none; + margin-bottom: -1px; } } } .sheet-body { padding: 5px 0; - height: calc(100% - 175px); + height: calc(100% - 140px); .attributes { margin: 0; padding: 0; diff --git a/src/scss/character.scss b/src/scss/character.scss index 56f7748..bba8afe 100644 --- a/src/scss/character.scss +++ b/src/scss/character.scss @@ -5,7 +5,7 @@ /* ----------------------------------------- */ .ose.sheet.actor.character { min-width: 450px; - min-height: 590px; + min-height: 550px; /* ----------------------------------------- */ /* Sheet Header */ diff --git a/src/templates/actors/partials/monster-attributes-tab.html b/src/templates/actors/partials/monster-attributes-tab.html index de5c26c..f06fef5 100644 --- a/src/templates/actors/partials/monster-attributes-tab.html +++ b/src/templates/actors/partials/monster-attributes-tab.html @@ -2,7 +2,7 @@
    • {{ localize "OSE.HealthShort" }}

      -
      +
      / @@ -138,35 +138,35 @@
      • - {{ localize "OSE.saves.death.short" }}

        + {{ localize "OSE.saves.death.long" }}
      • - {{ localize "OSE.saves.wand.short" }}

        + {{ localize "OSE.saves.wand.long" }}
      • - {{ localize "OSE.saves.paralysis.short" }}

        + {{ localize "OSE.saves.paralysis.long" }}
      • - {{ localize "OSE.saves.breath.short" }}

        + {{ localize "OSE.saves.breath.long" }}
      • - {{ localize "OSE.saves.spell.short" }}

        + {{ localize "OSE.saves.spell.long" }}
        From d9ec8023388b19ac939994742e65460289808edc Mon Sep 17 00:00:00 2001 From: U~man Date: Fri, 3 Jul 2020 17:13:53 +0200 Subject: [PATCH 15/19] 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 @@
          -
        • -

          {{localize 'OSE.MeleeShort'}}

          +
        • +

          {{localize 'OSE.MeleeShort'}}

          {{subtract data.thac0.mod.melee (subtract mods.str data.thac0.value)}} @@ -131,8 +131,8 @@
        • -
        • -

          {{localize 'OSE.MissileShort'}}

          +
        • +

          {{localize 'OSE.MissileShort'}}

          {{subtract data.thac0.mod.missile (subtract mods.dex data.thac0.value)}} diff --git a/src/templates/actors/partials/character-inventory-tab.html b/src/templates/actors/partials/character-inventory-tab.html index d3753da..798b132 100644 --- a/src/templates/actors/partials/character-inventory-tab.html +++ b/src/templates/actors/partials/character-inventory-tab.html @@ -12,7 +12,7 @@
          1. - {{#each weapons as |item|}} + {{#each owned.weapons as |item|}}
          2. @@ -63,7 +63,7 @@
            1. - {{#each armors as |item|}} + {{#each owned.armors as |item|}}
            2. @@ -109,7 +109,7 @@
              1. - {{#each inventory as |item|}} + {{#each owned.items as |item|}}
              2. diff --git a/src/templates/actors/partials/character-spells-tab.html b/src/templates/actors/partials/character-spells-tab.html index 8c08890..3e3a08a 100644 --- a/src/templates/actors/partials/character-spells-tab.html +++ b/src/templates/actors/partials/character-spells-tab.html @@ -1,12 +1,4 @@
                -
                -
              3. -
                -
                {{localize 'OSE.SpellDC'}}
                -
                -
              4. -
                {{#each spells as |spellGroup id|}}
                1. diff --git a/src/templates/actors/partials/monster-attributes-tab.html b/src/templates/actors/partials/monster-attributes-tab.html index f06fef5..ccb33b5 100644 --- a/src/templates/actors/partials/monster-attributes-tab.html +++ b/src/templates/actors/partials/monster-attributes-tab.html @@ -62,18 +62,18 @@
                {{!-- Skills and abilities --}} -
                -
                -

                {{localize 'OSE.panel.abilities'}}

                -
                +
                +
                +
              5. +
                {{localize 'OSE.panel.abilities'}} & {{localize 'OSE.panel.equipment'}}
                +
                {{#if owner}} - + {{/if}} -
                -
              6. -
                  -
                  +
                  + +
                    {{#each abilities as |item|}}
                  1. @@ -85,32 +85,17 @@
                    {{#if ../owner}} - - {{/if}}
              7. {{/each}} -
        -
      -
      - {{!-- 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 --}}
      From 579322181ba304c5f31b0e12ee900aaba0287361 Mon Sep 17 00:00:00 2001 From: U~man Date: Fri, 3 Jul 2020 17:46:11 +0200 Subject: [PATCH 16/19] ENH: Styling --- src/assets/back.png | Bin 0 -> 9845 bytes src/scss/actor-base.scss | 13 ++++++++----- src/scss/variables.scss | 1 + .../actors/partials/character-abilities-tab.html | 2 +- .../actors/partials/character-inventory-tab.html | 2 +- 5 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 src/assets/back.png diff --git a/src/assets/back.png b/src/assets/back.png new file mode 100644 index 0000000000000000000000000000000000000000..9b6f0569a169f2e4898248ecca2cd12d7c6ba7b8 GIT binary patch literal 9845 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 bDt!0
      -
        +
          {{#each abilities as |item|}}
        1. diff --git a/src/templates/actors/partials/character-inventory-tab.html b/src/templates/actors/partials/character-inventory-tab.html index 798b132..851f9e4 100644 --- a/src/templates/actors/partials/character-inventory-tab.html +++ b/src/templates/actors/partials/character-inventory-tab.html @@ -1,4 +1,4 @@ -
          +
        2. {{localize "OSE.items.Weapons"}}
          From 7c8ca4ae1f9207a2bc2710e48f2033882345b3f0 Mon Sep 17 00:00:00 2001 From: U~man Date: Fri, 3 Jul 2020 19:44:12 +0200 Subject: [PATCH 17/19] ENH: Monster tweaks --- src/lang/en.json | 3 +- src/module/actor/entity.js | 19 ++++++++++- src/scss/actor-base.scss | 9 +++++ src/scss/monster.scss | 14 ++++++++ src/template.json | 6 ++-- .../actors/dialogs/tweaks-dialog.html | 2 ++ .../partials/character-attributes-tab.html | 4 +-- .../partials/monster-attributes-tab.html | 33 ++++++++++--------- 8 files changed, 67 insertions(+), 23 deletions(-) diff --git a/src/lang/en.json b/src/lang/en.json index a7ff5c8..5d63ab1 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -2,6 +2,7 @@ "OSE.Edit": "Edit", "OSE.Delete": "Delete", "OSE.Add": "Add", + "OSE.Ok": "Ok", "OSE.Cancel": "Cancel", "OSE.Roll": "Roll", @@ -63,7 +64,7 @@ "OSE.MovementEncounterShort": "ENC", "OSE.MovementOverland": "Overland Movement Rate", "OSE.MovementOverlandShort": "OVE", - "OSE.MovementShort": "MR", + "OSE.MovementShort": "MV", "OSE.ArmorClass": "Armor Class", "OSE.ArmorClassShort": "AC", "OSE.AscArmorClassShort": "AAC", diff --git a/src/module/actor/entity.js b/src/module/actor/entity.js index 6c4f2ba..de6c976 100644 --- a/src/module/actor/entity.js +++ b/src/module/actor/entity.js @@ -44,7 +44,24 @@ export class OseActor extends Actor { rollAttack(attack, options={}) { const label = game.i18n.localize(`OSE.${attack}`); - const rollParts = ['1d20']; + const rollParts = ['1d20',]; + + const mods = this.computeModifiers(); + if (attack == 'Missile') { + rollParts.push( + '+', + mods.dex.toString(), + '+', + this.data.data.thac0.mod.missile.toString() + ); + } else if (attack == 'Melee') { + rollParts.push( + '+', + mods.str.toString(), + '+', + this.data.data.thac0.mod.melee.toString() + ); + } // Roll and return return OseDice.Roll({ diff --git a/src/scss/actor-base.scss b/src/scss/actor-base.scss index a3282b4..445b6d0 100644 --- a/src/scss/actor-base.scss +++ b/src/scss/actor-base.scss @@ -89,7 +89,9 @@ border-top-left-radius: 80px; box-shadow: 0 0 6px 1px $colorDark; font-size: 12px; + filter: brightness(0.9); &.active { + filter: none; z-index: 1; font-weight: bold; text-shadow: none; @@ -128,6 +130,10 @@ .attribute-value { text-align: center; padding: 4px; + .sep { + flex: 0 0 5px; + line-height: 24px; + } } .attribute-mod { position: absolute; @@ -160,6 +166,9 @@ .attribute-value { width: 45px; flex-grow: 0; + input { + padding: 0; + } } } } diff --git a/src/scss/monster.scss b/src/scss/monster.scss index 5cd0557..75f0482 100644 --- a/src/scss/monster.scss +++ b/src/scss/monster.scss @@ -5,5 +5,19 @@ .editor { height: 300px; } + .attributes .attribute.health { + min-width: 75px; + } + } + .attribute-group { + .attacks-description { + margin: 2px; + padding: 0; + text-align: center; + label { + color: $colorTan; + font-size: 10px; + } + } } } diff --git a/src/template.json b/src/template.json index e9aebb5..c4688e6 100644 --- a/src/template.json +++ b/src/template.json @@ -133,9 +133,7 @@ "appearing": "", "morale": 0 }, - "attacks": { - "value": 1 - } + "attacks": "" } }, "Item": { @@ -155,7 +153,7 @@ "qualities": "", "slow": false, "missile": true, - "ranged": true, + "melee": true, "cost": 0, "equipped": false, "weight": 0 diff --git a/src/templates/actors/dialogs/tweaks-dialog.html b/src/templates/actors/dialogs/tweaks-dialog.html index 42fff28..a6284f3 100644 --- a/src/templates/actors/dialogs/tweaks-dialog.html +++ b/src/templates/actors/dialogs/tweaks-dialog.html @@ -43,6 +43,7 @@ name="data.thac0.mod.melee" id="melee" value="{{data.thac0.mod.melee}}" + data-dtype="Number" />
        3. @@ -54,6 +55,7 @@ name="data.thac0.mod.missile" id="missile" value="{{data.thac0.mod.missile}}" + data-dtype="Number" />
    diff --git a/src/templates/actors/partials/character-attributes-tab.html b/src/templates/actors/partials/character-attributes-tab.html index df6db7a..2dbaaec 100644 --- a/src/templates/actors/partials/character-attributes-tab.html +++ b/src/templates/actors/partials/character-attributes-tab.html @@ -121,8 +121,8 @@
    -
  • -

    {{ localize "OSE.Thac0" }} +
  • +

    {{ localize "OSE.Thac0" }}

    diff --git a/src/templates/actors/partials/monster-attributes-tab.html b/src/templates/actors/partials/monster-attributes-tab.html index ccb33b5..2b18606 100644 --- a/src/templates/actors/partials/monster-attributes-tab.html +++ b/src/templates/actors/partials/monster-attributes-tab.html @@ -9,6 +9,13 @@
  • +
  • +

    {{ localize "OSE.HitDiceShort" }} +

    +
    + +
    +
  • {{#if config.ascendingAC}}

    @@ -33,14 +40,6 @@ data-dtype="Number" />

  • -
  • -

    {{ localize "OSE.AttacksShort" }} -

    -
    - -
    -
  • {{#if data.retainer.enabled}}
  • {{ localize "OSE.LoyaltyShort" }} @@ -65,13 +64,13 @@
  • -
    {{localize 'OSE.panel.abilities'}} & {{localize 'OSE.panel.equipment'}}
    -
    - {{#if owner}} - - {{/if}} -
    +
    {{localize 'OSE.panel.abilities'}} & {{localize 'OSE.panel.equipment'}}
    +
    + {{#if owner}} + + {{/if}} +
    1. {{#each abilities as |item|}} @@ -121,6 +120,10 @@
    {{!-- Saving throws --}}
    +
    + + +
    • From 7be97146c2adb10326e955b30d6868cefc1c680e Mon Sep 17 00:00:00 2001 From: U~man Date: Fri, 3 Jul 2020 23:05:49 +0200 Subject: [PATCH 18/19] ENH: Rolls! --- src/lang/en.json | 2 + src/module/actor/entity.js | 31 ++- src/module/dice.js | 142 +++++++++--- src/scss/actor-base.scss | 2 +- src/scss/apps.scss | 205 ++++++++++-------- src/scss/core.scss | 2 +- src/template.json | 1 + .../partials/character-attributes-tab.html | 37 +++- src/templates/chat/roll-attack.html | 7 + 9 files changed, 304 insertions(+), 125 deletions(-) create mode 100644 src/templates/chat/roll-attack.html diff --git a/src/lang/en.json b/src/lang/en.json index 5d63ab1..556e93c 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -71,6 +71,8 @@ "OSE.SpellDC": "Spell DC", "OSE.SpellDCShort": "DC", "OSE.Thac0": "THAC0", + "OSE.ABShort": "AB", + "OSE.AB": "Attack Bonus", "OSE.MeleeShort": "MEL", "OSE.Melee": "Melee", "OSE.MeleeBonus": "Melee Bonus", diff --git a/src/module/actor/entity.js b/src/module/actor/entity.js index de6c976..2874697 100644 --- a/src/module/actor/entity.js +++ b/src/module/actor/entity.js @@ -16,11 +16,18 @@ export class OseActor extends Actor { const label = game.i18n.localize(`OSE.saves.${save}.long`); const rollParts = ['1d20']; + const data = {...this.data, ...{ + rollData : { + type: 'Save', + stat: save + } + }}; + // Roll and return return OseDice.Roll({ event: options.event, parts: rollParts, - data: this.data, + data: data, speaker: ChatMessage.getSpeaker({ actor: this }), flavor: `${label} ${game.i18n.localize('OSE.SavingThrow')}`, title: `${label} ${game.i18n.localize('OSE.SavingThrow')}`, @@ -31,11 +38,18 @@ export class OseActor extends Actor { const label = game.i18n.localize(`OSE.scores.${score}.long`); const rollParts = ['1d20']; + const data = {...this.data, ...{ + rollData : { + type: 'Check', + stat: score + } + }}; + // Roll and return return OseDice.Roll({ event: options.event, parts: rollParts, - data: this.data, + data: data, speaker: ChatMessage.getSpeaker({ actor: this }), flavor: `${label} ${game.i18n.localize('OSE.AbilityCheck')}`, title: `${label} ${game.i18n.localize('OSE.AbilityCheck')}`, @@ -62,12 +76,23 @@ export class OseActor extends Actor { this.data.data.thac0.mod.melee.toString() ); } + if (game.settings.get('ose', 'ascendingAC')) { + rollParts.push('+', this.data.data.thac0.bba.toString()); + } + + const data = {...this.data, ...{ + rollData : { + type: 'Attack', + stat: attack, + mods: mods + } + }}; // Roll and return return OseDice.Roll({ event: options.event, parts: rollParts, - data: this.data, + data: data, speaker: ChatMessage.getSpeaker({ actor: this }), flavor: `${label} ${game.i18n.localize('OSE.Attack')}`, title: `${label} ${game.i18n.localize('OSE.Attack')}`, diff --git a/src/module/dice.js b/src/module/dice.js index 0a33078..9e37804 100644 --- a/src/module/dice.js +++ b/src/module/dice.js @@ -1,4 +1,111 @@ export class OseDice { + static digestResult(data, roll) { + let details = ""; + + // ATTACKS + let die = roll.parts[0].total; + if (data.rollData.type == "Attack") { + if (game.settings.get("ose", "ascendingAC")) { + let bba = data.data.thac0.bba; + bba += + data.rollData.stat == "Melee" + ? data.data.thac0.mod.melee + data.rollData.mods.str + : data.data.thac0.mod.missile + data.rollData.mods.dex; + details = `
      Failure (${bba})
      `; + if (die == 1) { + return details; + } + details = `
      Hits AC ${roll.total} (${bba})
      `; + } else { + // B/X Historic THAC0 Calculation + let thac = data.data.thac0.value; + thac -= + data.rollData.stat == "Melee" + ? data.data.thac0.mod.melee + data.rollData.mods.str + : data.data.thac0.mod.missile + data.rollData.mods.dex; + + details = `
      Failure (${thac})
      `; + if (thac - roll.total > 9) { + return details; + } + details = `
      Hits AC ${Math.clamped(thac - roll.total,-3,9)} (${thac})
      `; + } + } else if (data.rollData.type == "Save") { + // SAVING THROWS + let sv = data.data.saves[data.rollData.stat].value; + if (roll.total >= sv) { + details = `
      Success! (${sv})
      `; + } else { + details = `
      Failure (${sv})
      `; + } + } else if (data.rollData.type == "Check") { + // SCORE CHECKS + let sc = data.data.scores[data.rollData.stat].value; + if (die == 1 || (roll.total <= sc && die < 20)) { + details = `
      Success! (${sc})
      `; + } else { + details = `
      Failure (${sc})
      `; + } + } + return details; + } + + static async sendRoll( + parts = [], + data = {}, + title = null, + flavor = null, + speaker = null, + form = null + ) { + const template = "systems/ose/templates/chat/roll-attack.html"; + + let chatData = { + user: game.user._id, + speaker: speaker, + }; + + let templateData = { + title: title, + flavor: flavor, + data: data, + }; + + // Optionally include a situational bonus + if (form !== null) data["bonus"] = form.bonus.value; + if (data["bonus"]) parts.push(data["bonus"]); + + const roll = new Roll(parts.join(""), data).roll(); + + // Convert the roll to a chat message and return the roll + let rollMode = game.settings.get("core", "rollMode"); + rollMode = form ? form.rollMode.value : rollMode; + + templateData.details = OseDice.digestResult(data, roll); + roll.render().then((r) => { + templateData.rollOSE = r; + renderTemplate(template, templateData).then((content) => { + chatData.content = content; + chatData.sound = CONFIG.sounds.dice; + if (game.dice3d) { + game.dice3d + .showForRoll( + roll, + game.user, + true, + chatData.whisper, + chatData.blind + ) + .then((displayed) => ChatMessage.create(chatData)); + } else { + ChatMessage.create(chatData); + } + }); + }); + + return roll; + } + // eslint-disable-next-line no-unused-vars static async Roll({ parts = [], @@ -12,32 +119,10 @@ export class OseDice { } = {}) { let rollMode = game.settings.get("core", "rollMode"); let rolled = false; - let filtered = parts.filter(function (el) { - return el != "" && el; - }); - - const _roll = (form = null, raise = false) => { - // Optionally include a situational bonus - if (form !== null) data["bonus"] = form.bonus.value; - if (data["bonus"]) filtered.push(data["bonus"]); - - const roll = new Roll(filtered.join(""), data).roll(); - // Convert the roll to a chat message and return the roll - rollMode = form ? form.rollMode.value : rollMode; - roll.toMessage( - { - speaker: speaker, - flavor: flavor, - }, - { rollMode } - ); - rolled = true; - return roll; - }; const template = "systems/ose/templates/chat/roll-dialog.html"; let dialogData = { - formula: filtered.join(" "), + formula: parts.join(" "), data: data, rollMode: rollMode, rollModes: CONFIG.Dice.rollModes, @@ -48,7 +133,14 @@ export class OseDice { label: game.i18n.localize("OSE.Roll"), icon: '', callback: (html) => { - roll = _roll(html[0].children[0]); + roll = OseDice.sendRoll( + parts, + data, + title, + flavor, + speaker, + html[0].children[0] + ); }, }, cancel: { @@ -70,7 +162,7 @@ export class OseDice { buttons: buttons, default: "ok", close: () => { - resolve(rolled ? roll : false) + resolve(rolled ? roll : false); }, }).render(true); }); diff --git a/src/scss/actor-base.scss b/src/scss/actor-base.scss index 445b6d0..dd546f4 100644 --- a/src/scss/actor-base.scss +++ b/src/scss/actor-base.scss @@ -188,7 +188,7 @@ text-indent: 8px; } font-weight: 300; - font-size: 12px; + font-size: 13px; background: $darkBackground; color: white; input { diff --git a/src/scss/apps.scss b/src/scss/apps.scss index fcd39d7..0222691 100644 --- a/src/scss/apps.scss +++ b/src/scss/apps.scss @@ -1,97 +1,124 @@ - -.ose.chat-card { - font-style: normal; - font-size: 12px; - - .card-header { - padding: 3px 0; - border-top: 2px groove #FFF; - border-bottom: 2px groove #FFF; - - img { - flex: 0 0 36px; - margin-right: 5px; +.ose.chat-block { + margin: 0; + .chat-title { + background: $darkBackground; + border: 1px solid black; + border-radius: 3px; + color: white; + padding: 2px; + box-shadow: 0 0 2px #FFF inset; + text-align: center; + margin: 4px 0; + font-size: 16px; + } + .chat-details { + padding: 4px; + font-size: 13px; + .roll-result { + text-align: center; + &.roll-success { + color: #18520b; } - - h3 { - flex: 1; - margin: 0; - line-height: 36px; - color: $colorOlive; - &:hover { - color: #111; - text-shadow: 0 0 10px red; - } - } - } - - .card-content { - margin: 5px 0; - - h3 { - font-size: 12px; - margin: 0; - font-weight: bold; - } - - > * { - -webkit-user-select: text; - -moz-user-select: text; - -ms-user-select: text; - user-select: text; - } - } - - .card-buttons { - margin: 5px 0; - - span { - display: block; - line-height: 28px; - text-align: center; - border: 1px solid $colorTan; - } - - button { - font-size: 12px; - height: 24px; - line-height: 20px; - margin: 2px 0; - } - } - - .card-footer { - padding: 3px 0 0; - border-top: 2px groove #FFF; - - span { - border-right: 2px groove #FFF; - padding: 0 5px 0 0; - font-size: 10px; - - &:last-child { - border-right: none; - padding-right: 0; - } + &.roll-fail { + color: #aa0200; } } } - - .dice-roll .dice-total { - &.success { - color: inherit; - background: #c7d0c0; - border: 1px solid #006c00; +} + +.ose.chat-card { + font-style: normal; + font-size: 12px; + + .card-header { + padding: 3px 0; + border-top: 2px groove #fff; + border-bottom: 2px groove #fff; + + img { + flex: 0 0 36px; + margin-right: 5px; } - &.failure { - color: inherit; - background: #ffdddd; - border: 1px solid #6e0000; + + h3 { + flex: 1; + margin: 0; + line-height: 36px; + color: $colorOlive; + &:hover { + color: #111; + text-shadow: 0 0 10px red; + } } - &.critical { - color: green; + } + + .card-content { + margin: 5px 0; + + h3 { + font-size: 12px; + margin: 0; + font-weight: bold; } - &.fumble { - color: red; + + > * { + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; } - } \ No newline at end of file + } + + .card-buttons { + margin: 5px 0; + + span { + display: block; + line-height: 28px; + text-align: center; + border: 1px solid $colorTan; + } + + button { + font-size: 12px; + height: 24px; + line-height: 20px; + margin: 2px 0; + } + } + + .card-footer { + padding: 3px 0 0; + border-top: 2px groove #fff; + + span { + border-right: 2px groove #fff; + padding: 0 5px 0 0; + font-size: 10px; + + &:last-child { + border-right: none; + padding-right: 0; + } + } + } +} + +.dice-roll .dice-total { + &.success { + color: inherit; + background: #c7d0c0; + border: 1px solid #006c00; + } + &.failure { + color: inherit; + background: #ffdddd; + border: 1px solid #6e0000; + } + &.critical { + color: green; + } + &.fumble { + color: red; + } +} diff --git a/src/scss/core.scss b/src/scss/core.scss index d90a3f0..c146942 100644 --- a/src/scss/core.scss +++ b/src/scss/core.scss @@ -37,4 +37,4 @@ .resizable { overflow: auto; } -} +} \ No newline at end of file diff --git a/src/template.json b/src/template.json index c4688e6..0841ef6 100644 --- a/src/template.json +++ b/src/template.json @@ -24,6 +24,7 @@ }, "thac0": { "value": 19, + "bba": 0, "mod": { "missile": 0, "melee": 0 diff --git a/src/templates/actors/partials/character-attributes-tab.html b/src/templates/actors/partials/character-attributes-tab.html index 2dbaaec..6b8f2e4 100644 --- a/src/templates/actors/partials/character-attributes-tab.html +++ b/src/templates/actors/partials/character-attributes-tab.html @@ -114,15 +114,32 @@
      • -

        {{localize 'OSE.MeleeShort'}}

        +

        + {{localize 'OSE.MeleeShort'}}

        + {{#if config.ascendingAC}} + {{add data.thac0.mod.melee (add mods.str data.thac0.bba)}} + {{else}} {{subtract data.thac0.mod.melee (subtract mods.str data.thac0.value)}} + {{/if}}
      • -
      • -

        {{ localize "OSE.Thac0" }} + {{#if config.ascendingAC}} +
      • +

        {{ localize "OSE.ABShort"}} +

        +
        +
        + +
        +
        +
      • + {{else}} +
      • +

        {{ localize "OSE.Thac0"}}

        @@ -131,11 +148,17 @@
      • + {{/if}}
      • -

        {{localize 'OSE.MissileShort'}}

        +

        + {{localize 'OSE.MissileShort'}}

        + {{#if config.ascendingAC}} + {{add data.thac0.mod.missile (add mods.dex data.thac0.bba)}} + {{else}} {{subtract data.thac0.mod.missile (subtract mods.dex data.thac0.value)}} + {{/if}}
      • @@ -144,7 +167,8 @@
        • -

          {{localize 'OSE.MovementEncounterShort'}}

          +

          + {{localize 'OSE.MovementEncounterShort'}}

          {{divide data.movement.base 3}} @@ -160,7 +184,8 @@
        • -

          {{localize 'OSE.MovementOverlandShort'}}

          +

          + {{localize 'OSE.MovementOverlandShort'}}

          {{divide data.movement.base 5}} diff --git a/src/templates/chat/roll-attack.html b/src/templates/chat/roll-attack.html new file mode 100644 index 0000000..81cca7a --- /dev/null +++ b/src/templates/chat/roll-attack.html @@ -0,0 +1,7 @@ +
          +
          +

          {{title}}

          + {{#if details}}
          {{{details}}}
          {{/if}} + {{#if rollOSE}}
          {{{rollOSE}}}
          {{/if}} +
          +
          \ No newline at end of file From 72c96d1df5f336f50095b63bdb9e7d75d76575b8 Mon Sep 17 00:00:00 2001 From: U~man Date: Fri, 3 Jul 2020 23:16:47 +0200 Subject: [PATCH 19/19] ENH: Weapon attack --- src/lang/en.json | 2 +- src/module/item/entity.js | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/lang/en.json b/src/lang/en.json index 556e93c..53dc372 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -42,7 +42,7 @@ "OSE.scores.cha.long": "Charisma", "OSE.scores.cha.short": "CHA", - "OSE.SavingThrow": "Saving Throw", + "OSE.SavingThrow": "Save", "OSE.saves.death.short": "D", "OSE.saves.death.long": "Death, Poison", "OSE.saves.wand.short": "W", diff --git a/src/module/item/entity.js b/src/module/item/entity.js index 78edbf4..7e1444b 100644 --- a/src/module/item/entity.js +++ b/src/module/item/entity.js @@ -42,11 +42,26 @@ export class OseItem extends Item { return data; } + rollWeapon() { + if (this.data.data.missile) { + this.actor.rollAttack('Missile'); + return true; + } else if (this.data.data.melee) { + this.actor.rollAttack('Melee'); + return true; + } + return false; + } + /** * Roll the item to Chat, creating a chat card which contains follow up attack or damage roll options * @return {Promise} */ async roll({ configureDialog = true } = {}) { + console.log(this.data) + if (this.data.type == 'weapon') { + if (this.rollWeapon()) return; + } // Basic template rendering data const token = this.actor.token; const templateData = {