From b98f593b8604cec93bee06a70ed2aa2004448ffe Mon Sep 17 00:00:00 2001 From: Russell Larkin Date: Tue, 6 Aug 2024 20:09:18 +0100 Subject: [PATCH] #81 - Update for Foundry VTT 12.330 and dnd5e 3.3. --- module.json | 10 ++-- scripts/constants.js | 11 +++- scripts/counters.js | 20 +++++-- scripts/house-rules.js | 4 +- scripts/patches/prepare-encumbrance.js | 12 +++-- scripts/sheets/character-sheet.js | 2 +- styles/custom-dnd5e-character-sheet.css | 8 ++- styles/custom-dnd5e-counters.css | 22 ++++---- templates/sheet/character-details.hbs | 70 +++++++++---------------- templates/sheet/character-sheet-2.hbs | 44 +++++++++------- 10 files changed, 112 insertions(+), 91 deletions(-) diff --git a/module.json b/module.json index e6397f6..ef29747 100644 --- a/module.json +++ b/module.json @@ -6,8 +6,8 @@ "library": "false", "compatibility": { "minimum": 12.325, - "verified": 12.328, - "maximum": 12.328 + "verified": 12.330, + "maximum": 12 }, "authors": [ { @@ -37,9 +37,9 @@ "type": "system", "compatibility": [ { - "minimum": "3.2.0", - "verified": "3.2.1", - "maximum": "3.2" + "minimum": "3.3.1", + "verified": "3.3.1", + "maximum": "3.3" } ] } diff --git a/scripts/constants.js b/scripts/constants.js index 3ede0e9..b746973 100644 --- a/scripts/constants.js +++ b/scripts/constants.js @@ -521,7 +521,16 @@ export const SHEET_TYPE = { group: false, item: false, legacy: true, - npc: false + npc: true + }, + ActorSheet5eNPC2: { + countersSetting: CONSTANTS.COUNTERS.SETTING.NPC_COUNTERS.KEY, + character: false, + custom: false, + group: false, + item: false, + legacy: false, + npc: true }, GroupActorSheet: { countersSetting: CONSTANTS.COUNTERS.SETTING.GROUP_COUNTERS.KEY, diff --git a/scripts/counters.js b/scripts/counters.js index 7dd477b..fd44d51 100644 --- a/scripts/counters.js +++ b/scripts/counters.js @@ -164,6 +164,8 @@ function onTriggerZeroHp (actor) { const counters = getCounters(actor) Object.entries(counters).forEach(([source, counters2]) => { + if (!counters2) return + Object.entries(counters2).forEach(([key, value]) => { const triggers = value.triggers if (!triggers) return @@ -187,6 +189,8 @@ function onTriggerHalfHp (actor) { const counters = getCounters(actor) Object.entries(counters).forEach(([source, counters2]) => { + if (!counters2) return + Object.entries(counters2).forEach(([key, value]) => { const triggers = value.triggers if (!triggers) return @@ -207,6 +211,8 @@ function onTriggerCounterValue (actor, data) { const counters = getCounters(actor) Object.entries(counters).forEach(([source, counters2]) => { + if (!counters2) return + Object.entries(counters2).forEach(([key, value]) => { key = (source === 'entity') ? `counters.${key}` : key const counterValue = (source === 'entity') ? data.flags[MODULE.ID][key]?.value : data.flags[MODULE.ID][key] @@ -229,6 +235,8 @@ function onTriggerRest (restType, actor) { const counters = getCounters(actor) Object.entries(counters).forEach(([source, counters2]) => { + if (!counters2) return + Object.entries(counters2).forEach(([key, value]) => { const triggers = value.triggers if (!triggers) return @@ -397,8 +405,6 @@ function addCounters (app, html, data, sheetType) { if (!data?.editable && checkEmpty(counters.world) && checkEmpty(counters.entity)) return - const detailsRightDiv = html[0].querySelector('.tab.details > .right') - const detailsRightTopDiv = detailsRightDiv.querySelector('.top') const countersDiv = createCountersDiv(actor, data) const ul = countersDiv.appendChild(document.createElement('ul')) let someCounters = false @@ -415,7 +421,15 @@ function addCounters (app, html, data, sheetType) { } if (data?.editable || someCounters) { - detailsRightTopDiv.after(countersDiv) + if (sheetType.character) { + const detailsRightDiv = html[0].querySelector('.tab.details > .right') + const detailsRightTopDiv = detailsRightDiv.querySelector('.top') + detailsRightTopDiv.after(countersDiv) + } else { + const sidebarDiv = html[0].querySelector('.sidebar') + sidebarDiv.insertBefore(countersDiv, sidebarDiv.firstChild) + } + if (!someCounters) { countersDiv.classList.add('empty') } diff --git a/scripts/house-rules.js b/scripts/house-rules.js index 27f5865..28eaf22 100644 --- a/scripts/house-rules.js +++ b/scripts/house-rules.js @@ -375,7 +375,7 @@ function setDeathSavesRollMode (actor, rollData) { /** * Recalculate Damage - * Trigger by the 'dnd5e.preApplyDamage' hook + * Triggered by the 'dnd5e.preApplyDamage' hook * If 'Apply Negative HP' is enabled, recalculate damage to apply a negative value to HP * @param {object} actor The actor * @param {number} amount The damage amount @@ -389,7 +389,7 @@ function recalculateDamage (actor, amount, updates, options) { const newHpTemp = amount > 0 ? Math.max(hpTemp - amount, 0) : (updates['system.attribute.hp.temp'] ?? hpTemp) const startHp = (getSetting(CONSTANTS.HIT_POINTS.SETTING.NEGATIVE_HP_HEAL_FROM_ZERO)) ? 0 : hpValue const newHpValue = amount > 0 - ? hpValue - (amount - Math.mind(amount, hpTemp)) + ? hpValue - (amount - Math.min(amount, hpTemp)) : Math.min(startHp - amount, hpMax) updates['system.attributes.hp.temp'] = newHpTemp diff --git a/scripts/patches/prepare-encumbrance.js b/scripts/patches/prepare-encumbrance.js index 62292e1..0888865 100644 --- a/scripts/patches/prepare-encumbrance.js +++ b/scripts/patches/prepare-encumbrance.js @@ -11,8 +11,10 @@ export function patchPrepareEncumbrance () { * @this {CharacterData|NPCData|VehicleData} * @param {object} rollData The Actor's roll data. */ -async function prepareEncumbrancePatch (rollData) { +async function prepareEncumbrancePatch (rollData, { validateItem } = {}) { + const convertWeight = dnd5e.utils.convertWeight const simplifyBonus = dnd5e.utils.simplifyBonus + const equippedMod = (this.parent?.type === 'character') ? getSetting(CONSTANTS.ENCUMBRANCE.EQUIPPED_ITEM_WEIGHT_MODIFIER.SETTING.KEY) || 0 : 1 const proficientEquippedMod = (this.parent?.type === 'character') ? getSetting(CONSTANTS.ENCUMBRANCE.PROFICIENT_EQUIPPED_ITEM_WEIGHT_MODIFIER.SETTING.KEY) || 0 : 1 const unequippedMod = (this.parent?.type === 'character') ? getSetting(CONSTANTS.ENCUMBRANCE.UNEQUIPPED_ITEM_WEIGHT_MODIFIER.SETTING.KEY) || 0 : 1 @@ -25,7 +27,7 @@ async function prepareEncumbrancePatch (rollData) { // Get the total weight from items let weight = this.parent.items - .filter(item => !item.container) + .filter(item => !item.container && (validateItem?.(item) ?? true)) .reduce((weight, item) => { const equipped = item.system.equipped const proficient = item.system.prof?.multiplier >= 1 @@ -39,7 +41,11 @@ async function prepareEncumbrancePatch (rollData) { if (game.settings.get('dnd5e', 'currencyWeight') && currency) { const numCoins = Object.values(currency).reduce((val, denom) => val + Math.max(denom, 0), 0) const currencyPerWeight = config.currencyPerWeight[unitSystem] - weight += numCoins / currencyPerWeight + weight += convertWeight( + numCoins / currencyPerWeight, + config.baseUnits.default[unitSystem], + baseUnits[unitSystem] + ) } // Determine the Encumbrance size class diff --git a/scripts/sheets/character-sheet.js b/scripts/sheets/character-sheet.js index 443a439..b2cd996 100644 --- a/scripts/sheets/character-sheet.js +++ b/scripts/sheets/character-sheet.js @@ -27,7 +27,7 @@ export class CustomDnd5eSheetCharacter2 extends dnd5e.applications.actor.ActorSh /** @inheritDoc */ static get defaultOptions () { return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['custom-dnd5e', 'dnd5e2', 'sheet', 'actor', 'character'] + classes: ['custom-dnd5e', 'dnd5e2', 'sheet', 'actor', 'character', 'vertical-tabs'] }) } diff --git a/styles/custom-dnd5e-character-sheet.css b/styles/custom-dnd5e-character-sheet.css index 5d17431..51792d0 100644 --- a/styles/custom-dnd5e-character-sheet.css +++ b/styles/custom-dnd5e-character-sheet.css @@ -122,8 +122,8 @@ margin-left: 1px; } -.custom-dnd5e.dnd5e2.sheet.actor.character .sheet-body .sidebar .card .stats .top .ac { - padding-bottom: 0.25rem; +.custom-dnd5e.dnd5e2.sheet.actor.character .sheet-body .sidebar .card .stats .top { + justify-content: center; } .custom-dnd5e.dnd5e2 .death-saves .pips:first-child { @@ -266,6 +266,10 @@ flex-wrap: wrap; } +.custom-dnd5e.dnd5e2.sheet.actor .sheet-body .main-content .tab-body .tab:not(.active) { + display: none; +} + .custom-dnd5e.dnd5e2.sheet.actor.character .tab-details .tab-body { display: flex; padding-top: 0; diff --git a/styles/custom-dnd5e-counters.css b/styles/custom-dnd5e-counters.css index 34ecd3d..3afe68b 100644 --- a/styles/custom-dnd5e-counters.css +++ b/styles/custom-dnd5e-counters.css @@ -24,7 +24,7 @@ width: 100%; } -.dnd5e-theme-dark .character .custom-dnd5e-counters-counter input { +.dnd5e-theme-dark :is(.character, .npc) .custom-dnd5e-counters-counter input { color: var(--color-text-dark-primary); } @@ -42,7 +42,7 @@ justify-content: center; } -.dnd5e-theme-dark .character .custom-dnd5e-counters-counter i { +.dnd5e-theme-dark :is(.character, .npc) .custom-dnd5e-counters-counter i { color: var(--dnd5e-color-blue-gray-3); } @@ -54,7 +54,7 @@ justify-content: center; } -.dnd5e-theme-dark .character .dnd5e-custom-counters-separator { +.dnd5e-theme-dark :is(.character, .npc) .dnd5e-custom-counters-separator { color: var(--color-text-dark-primary); } @@ -73,7 +73,7 @@ grid-column-end: 5; } -.dnd5e-theme-dark .character .custom-dnd5e-counters-fraction-group { +.dnd5e-theme-dark :is(.character, .npc) .custom-dnd5e-counters-fraction-group { background-color: var(--dnd5e-color-iron-gray); border: 1px solid var(--dnd5e-color-blue-gray-3); } @@ -97,7 +97,7 @@ background-color: var(--dnd5e-color-parchment); } -.dnd5e-theme-dark .character .custom-dnd5e-counters-number > input { +.dnd5e-theme-dark :is(.character, .npc) .custom-dnd5e-counters-number > input { background-color: var(--dnd5e-color-iron-gray); border: 1px solid var(--dnd5e-color-blue-gray-3); } @@ -110,7 +110,7 @@ grid-template-columns: 0.75fr 1.25fr 0.75fr 1.25fr; } -.dnd5e-theme-dark .character .custom-dnd5e-counters-success-failure { +.dnd5e-theme-dark :is(.character, .npc) .custom-dnd5e-counters-success-failure { background-color: var(--dnd5e-color-iron-gray); border: 1px solid var(--dnd5e-color-blue-gray-3); } @@ -126,12 +126,12 @@ border-radius: 0; } -.dnd5e-theme-dark .character .custom-dnd5e-counters-success-failure > input, -.dnd5e-theme-dark .character .custom-dnd5e-counters-success-failure +.dnd5e-theme-dark :is(.character, .npc) .custom-dnd5e-counters-success-failure > input, +.dnd5e-theme-dark :is(.character, .npc) .custom-dnd5e-counters-success-failure > input:disabled:hover .custom-dnd5e-counters-success-failure > input, -.dnd5e-theme-dark .character .custom-dnd5e-counters-success-failure > input:disabled:hover { +.dnd5e-theme-dark :is(.character, .npc) .custom-dnd5e-counters-success-failure > input:disabled:hover { border-left: 1px dashed var(--dnd5e-color-blue-gray-3); } @@ -144,8 +144,8 @@ border-right: 1px solid var(--color-border-light-tertiary); } -.dnd5e-theme-dark .character .custom-dnd5e-counters-success-failure > input:first-of-type, -.dnd5e-theme-dark .character .custom-dnd5e-counters-success-failure +.dnd5e-theme-dark :is(.character, .npc) .custom-dnd5e-counters-success-failure > input:first-of-type, +.dnd5e-theme-dark :is(.character, .npc) .custom-dnd5e-counters-success-failure > input:first-of-type:disabled:hover .custom-dnd5e-counters-success-failure > input:first-of-type, diff --git a/templates/sheet/character-details.hbs b/templates/sheet/character-details.hbs index 1e52df7..5fcb295 100644 --- a/templates/sheet/character-details.hbs +++ b/templates/sheet/character-details.hbs @@ -11,7 +11,7 @@
{{ abbreviation }}
{{/if}} {{ label }} -
{{ sign }}{{ mod }}
+
{{ dnd5e-formatModifier total }}
{{#if @root.editable}} @@ -24,13 +24,17 @@ {{/inline}} {{#*inline "ability-prof"}} -
  • +
  • + {{#if isConcentration}} + + {{else}} + {{/if}} {{ label }} {{ abbr }} -
    {{ sign }}{{ mod }}
    +
    {{ dnd5e-formatModifier save }}
    {{#if @root.editable}} @@ -39,38 +43,6 @@
  • {{/inline}} -{{#*inline "traits"}} - {{#if (or @root.editable values)}} -
    -

    - {{#if icon}} - {{~else if svg}}{{/if}} - {{ localize label }} - {{#if @root.editable}} - - - - {{/if}} -

    - -
    - {{/if}} -{{/inline}} -
    {{!-- Ability Scores --}} @@ -254,27 +226,37 @@ {{/if}} {{!-- Resistances --}} - {{> "traits" values=traits.dr key="dr" color="green" icon="fas fa-shield-halved" label="DND5E.Resistances" }} + {{> "dnd5e.actor-trait-pills" values=traits.dr key="dr" color="green" icon="fas fa-shield-halved" + label="DND5E.Resistances" }} {{!-- Immunities --}} {{#if editable}} - {{> "traits" values=traits.di key="di" color="green" icon="fas fa-shield" label="DND5E.DamImm" }} + {{> "dnd5e.actor-trait-pills" values=traits.di key="di" color="green" icon="fas fa-shield" + label="DND5E.DamImm" }} {{else}} - {{> "traits" values=traits.di key="di" color="green" icon="fas fa-shield" label="DND5E.Immunities" }} + {{> "dnd5e.actor-trait-pills" values=traits.di key="di" color="green" icon="fas fa-shield" + label="DND5E.Immunities" }} {{/if}} - {{> "traits" values=traits.ci key="ci" color="green" svg="rosa-shield" label="DND5E.ConImm" }} + {{> "dnd5e.actor-trait-pills" values=traits.ci key="ci" color="green" svg="rosa-shield" label="DND5E.ConImm" }} {{!-- Vulnerabilities --}} - {{> "traits" values=traits.dv key="dv" color="maroon" icon="fas fa-heart-crack" label="DND5E.Vulnerabilities" }} + {{> "dnd5e.actor-trait-pills" values=traits.dv key="dv" color="maroon" icon="fas fa-heart-crack" + label="DND5E.Vulnerabilities" }} + + {{!-- Damage Modification --}} + {{> "dnd5e.actor-trait-pills" values=traits.dm key="dm" icon="fas fa-heart-circle-plus" + label="DND5E.DamageModification.Label" }} {{!-- Armor --}} - {{> "traits" values=traits.armor key="armor" svg="checked-shield" label="DND5E.Armor" }} + {{> "dnd5e.actor-trait-pills" values=traits.armor key="armor" svg="checked-shield" label="DND5E.Armor" }} {{!-- Weapons --}} - {{> "traits" values=traits.weapon key="weapon" svg="trait-weapon-proficiencies" label="TYPES.Item.weaponPl" }} + {{> "dnd5e.actor-trait-pills" values=traits.weapon key="weapon" svg="trait-weapon-proficiencies" + label="TYPES.Item.weaponPl" }} {{!-- Languages --}} - {{> "traits" values=traits.languages key="languages" icon="fas fa-flag" label="DND5E.Languages" }} + {{> "dnd5e.actor-trait-pills" values=traits.languages key="languages" icon="fas fa-flag" + label="DND5E.Languages" }}
    - \ No newline at end of file + diff --git a/templates/sheet/character-sheet-2.hbs b/templates/sheet/character-sheet-2.hbs index 26e5197..3a0b84b 100644 --- a/templates/sheet/character-sheet-2.hbs +++ b/templates/sheet/character-sheet-2.hbs @@ -15,7 +15,7 @@ {{else}} - {{ sign }}{{ mod }} + {{ dnd5e-formatModifier mod }} {{/if}}
    @@ -52,7 +52,9 @@
    {{!-- Level --}} -
    {{ system.details.level }}
    +
    + {{ system.details.level }} +
    {{!-- Inspiration --}}
    {{!-- AC --}} - {{!-- Death Saves --}} @@ -380,11 +384,8 @@ {{/with}} {{!-- Modifiers --}} - {{else if modifier}} - {{#with modifier}} - {{ sign }} - {{ abs }} - {{/with}} + {{else if modifier includeZero=true}} + {{ dnd5e-formatModifier modifier }} {{!-- Passive Score --}} {{#if passive}} @@ -423,8 +424,8 @@ {{ resource.value }} {{/if}} / - {{#if @root.actor.isOwner}} - {{else}} @@ -473,12 +474,13 @@ {{!-- Features --}}
    - {{> "dnd5e.character-features" sections=features }} + {{> "dnd5e.creature-features" sections=features.sections filters=features.filters + showClassDrop=true }}
    {{!-- Spells --}}
    - {{> "dnd5e.character-spells" }} + {{> "dnd5e.creature-spells" }}
    {{!-- Effects --}} @@ -500,4 +502,8 @@ aria-label="{{ "SIDEBAR.Create" type=(localize "DOCUMENT.Item") }}"> + + {{!-- Warnings --}} + {{> "dnd5e.actor-warnings-dialog" }} +