diff --git a/gulpfile.js b/gulpfile.js index 45479a5c..1a81f5ae 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -3,7 +3,7 @@ var gulp = require('gulp'); var less = require('gulp-less'); gulp.task('less', function (cb) { - gulp.src('styles/daggerheart.less').pipe(less()).pipe(gulp.dest('styles')); + gulp.src('styles/daggerheart.less').pipe(less()).on('error', console.error.bind(console)).pipe(gulp.dest('styles')); cb(); }); diff --git a/lang/en.json b/lang/en.json index 99a75f83..b4b1410e 100755 --- a/lang/en.json +++ b/lang/en.json @@ -758,15 +758,20 @@ } }, "GroupRollSelect": { - "title": "Group Roll", - "aidingCharacters": "Aiding Characters", + "cancelConfirmText": "Are you sure you want to cancel the Group Roll? This will close it for all other players too.", + "cancelConfirmTitle": "Cancel Group Roll", + "initializationTitle": "Character Selection", + "finishGroupRoll": "Finish Group Roll", "leader": "Leader", "leaderRoll": "Leader Roll", + "members": "Members", "openDialogForAll": "Open Dialog For All", + "removeRoll": "Remove Roll", + "resultsHint": "Results will appear when characters roll", + "selectLeaderHint": "Select one Character to be the leader", + "selectParticipantsHint": "Select one Character to be the leader", "startGroupRoll": "Start Group Roll", - "finishGroupRoll": "Finish Group Roll", - "cancelConfirmTitle": "Cancel Group Roll", - "cancelConfirmText": "Are you sure you want to cancel the Group Roll? This will close it for all other players too." + "title": "Group Roll" }, "TokenConfig": { "actorSizeUsed": "Actor size is set, determining the dimensions" diff --git a/module/applications/dialogs/groupRollDialog.mjs b/module/applications/dialogs/groupRollDialog.mjs index a47dd0a8..df03a061 100644 --- a/module/applications/dialogs/groupRollDialog.mjs +++ b/module/applications/dialogs/groupRollDialog.mjs @@ -37,17 +37,17 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat tag: 'form', id: 'GroupRollDialog', classes: ['daggerheart', 'views', 'dh-style', 'dialog', 'group-roll-dialog'], - position: { width: 550, height: 'auto' }, + position: { width: 390, height: 'auto' }, + window: { + icon: 'fa-solid fa-users' + }, actions: { toggleSelectMember: this.#toggleSelectMember, startGroupRoll: this.#startGroupRoll, makeRoll: this.#makeRoll, removeRoll: this.#removeRoll, rerollDice: this.#rerollDice, - makeLeaderRoll: this.#makeLeaderRoll, - removeLeaderRoll: this.#removeLeaderRoll, - rerollLeaderDice: this.#rerollLeaderDice, - markSuccessfull: this.#markSuccessfull, + markSuccessful: this.#markSuccessful, cancelRoll: this.#onCancelRoll, finishRoll: this.#finishRoll }, @@ -59,17 +59,21 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat id: 'initialization', template: 'systems/daggerheart/templates/dialogs/groupRollDialog/initialization.hbs' }, + main: { + id: 'main', + template: 'systems/daggerheart/templates/dialogs/groupRollDialog/main.hbs' + }, leader: { id: 'leader', - template: 'systems/daggerheart/templates/dialogs/groupRollDialog/leader.hbs' + template: 'systems/daggerheart/templates/dialogs/groupRollDialog/parts/member.hbs' }, - groupRoll: { - id: 'groupRoll', - template: 'systems/daggerheart/templates/dialogs/groupRollDialog/groupRoll.hbs' + result: { + id: 'result', + template: 'systems/daggerheart/templates/dialogs/groupRollDialog/parts/result.hbs' }, footer: { id: 'footer', - template: 'systems/daggerheart/templates/dialogs/groupRollDialog/footer.hbs' + template: 'systems/daggerheart/templates/dialogs/groupRollDialog/parts/footer.hbs' } }; @@ -89,40 +93,14 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat } _configureRenderParts(options) { - const { initialization, leader, groupRoll, footer } = super._configureRenderParts(options); - const augmentedParts = { initialization }; + const parts = super._configureRenderParts(options); for (const memberKey of Object.keys(this.party.system.groupRoll.aidingCharacters)) { - augmentedParts[memberKey] = { + parts[memberKey] = { id: memberKey, - template: 'systems/daggerheart/templates/dialogs/groupRollDialog/groupRollMember.hbs' + template: 'systems/daggerheart/templates/dialogs/groupRollDialog/parts/member.hbs' }; } - - augmentedParts.leader = leader; - augmentedParts.groupRoll = groupRoll; - augmentedParts.footer = footer; - - return augmentedParts; - } - - /**@inheritdoc */ - async _onRender(context, options) { - await super._onRender(context, options); - - if (this.element.querySelector('.team-container')) return; - - if (this.tabGroups.application !== this.constructor.PARTS.initialization.id) { - const initializationPart = this.element.querySelector('.initialization-container'); - initializationPart.insertAdjacentHTML('afterend', '
'); - initializationPart.insertAdjacentHTML( - 'afterend', - `
${game.i18n.localize('DAGGERHEART.APPLICATIONS.GroupRollSelect.aidingCharacters')}
` - ); - - const teamContainer = this.element.querySelector('.team-container'); - for (const memberContainer of this.element.querySelectorAll('.team-member-container')) - teamContainer.appendChild(memberContainer); - } + return parts; } async _prepareContext(_options) { @@ -134,6 +112,7 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat context.data = this.party.system.groupRoll; context.traitOptions = CONFIG.DH.ACTOR.abilities; context.members = {}; + context.aidKeys = Object.keys(this.party.system.groupRoll.aidingCharacters); context.allHaveRolled = Object.keys(context.data.participants).every(key => { const data = context.data.participants[key]; return Boolean(data.rollData); @@ -145,6 +124,7 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat async _preparePartContext(partId, context, options) { const partContext = await super._preparePartContext(partId, context, options); partContext.partId = partId; + partContext.leader = this.getRollCharacterData(this.party.system.groupRoll.leader); switch (partId) { case 'initialization': @@ -162,19 +142,14 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat partContext.canStartGroupRoll = selectedMembers.length > 1 && this.leader?.memberId; partContext.openForAllPlayers = this.openForAllPlayers; break; - case 'leader': - partContext.leader = this.getRollCharacterData(this.party.system.groupRoll.leader); - break; - case 'groupRoll': + case 'result': const leader = this.party.system.groupRoll.leader; partContext.hasRolled = leader?.rollData || - Object.values(this.party.system.groupRoll?.aidingCharacters ?? {}).some( - x => x.successfull !== null - ); + Object.values(this.party.system.groupRoll?.aidingCharacters ?? {}).some(x => x.successful !== null); const { modifierTotal, modifiers } = Object.values(this.party.system.groupRoll.aidingCharacters).reduce( (acc, curr) => { - const modifier = curr.successfull === true ? 1 : curr.successfull === false ? -1 : null; + const modifier = curr.successful === true ? 1 : curr.successful === false ? -1 : null; if (modifier) { acc.modifierTotal += modifier; acc.modifiers.push(modifier); @@ -200,7 +175,7 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat case 'footer': partContext.canFinishRoll = Boolean(this.party.system.groupRoll.leader?.rollData) && - Object.values(this.party.system.groupRoll.aidingCharacters).every(x => x.successfull !== null); + Object.values(this.party.system.groupRoll.aidingCharacters).every(x => x.successful !== null); break; } @@ -216,20 +191,42 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat if (!data) return {}; const actor = game.actors.get(data.id); + const isLeader = data === this.party.system.groupRoll.leader; + + const roll = data.roll; + const withTypeSuffix = !roll ? null : roll.isCritical ? 'criticalShort' : roll.withHope ? 'hope' : 'fear'; + const thing = withTypeSuffix ? _loc(`DAGGERHEART.GENERAL.${withTypeSuffix}`) : null; return { ...data, + type: isLeader ? 'leader' : 'aid', + basePath: isLeader ? 'system.groupRoll.leader' : `system.groupRoll.aidingCharacters.${data.id}`, + rollChoiceLabel: _loc(CONFIG.DH.ACTOR.abilities[data.rollChoice]?.label), roll: data.roll, - isEditable: actor.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER), + isEditable: actor?.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER), key: partId, readyToRoll: Boolean(data.rollChoice), - hasRolled: Boolean(data.rollData) + hasRolled: Boolean(data.rollData), + modifier: data.successful ? 1 : data.successful === false ? -1 : 0, + withLabelShort: thing ? _loc('DAGGERHEART.GENERAL.withThing', { thing }) : null }; } + #getCharacterDataById(id) { + if (!id) return null; + + const groupRoll = this.party.system.groupRoll; + if (id === 'leader' || id === groupRoll.leader?.id) { + return { data: groupRoll.leader, basePath: 'system.groupRoll.leader' }; + } else if (id in groupRoll.aidingCharacters) { + return { data: groupRoll.aidingCharacters[id], basePath: `system.groupRoll.aidingCharacters.${id}` }; + } + + return null; + } + static async updateData(event, _, formData) { const partyData = foundry.utils.expandObject(formData.object); - this.updatePartyData(partyData, this.getUpdatingParts(event.target)); } @@ -256,16 +253,16 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat } getUpdatingParts(target) { - const { initialization, leader, groupRoll, footer } = this.constructor.PARTS; + const { initialization, leader, result, footer } = this.constructor.PARTS; const isInitialization = this.tabGroups.application === initialization.id; - const updatingMember = target.closest('.team-member-container')?.dataset?.memberKey; - const updatingLeader = target.closest('.main-character-outer-container'); + const updatingMember = target.closest('.member-roll-container.aid')?.dataset?.memberKey; + const updatingLeader = target.closest('.member-roll-container.leader'); return [ ...(isInitialization ? [initialization.id] : []), ...(updatingMember ? [updatingMember] : []), ...(updatingLeader ? [leader.id] : []), - ...(!isInitialization ? [groupRoll.id, footer.id] : []) + ...(!isInitialization ? [result.id, footer.id] : []) ]; } @@ -304,6 +301,9 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat static #toggleSelectMember(_, button) { const member = this.partyMembers.find(x => x.id === button.dataset.id); member.selected = !member.selected; + if (this.leader?.memberId === member.id) { + this.leader = null; + } this.render(); } @@ -343,11 +343,14 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat } //#endregion - async makeRoll(button, characterData, path) { - const actor = game.actors.find(x => x.id === characterData.id); + /** @this GroupRollDialog */ + static async #makeRoll(_event, button) { + const member = button.closest('[data-member-key]').dataset.memberKey; + const { data, basePath } = this.#getCharacterDataById(member); + const actor = game.actors.find(x => x.id === data.id); if (!actor) return; - const result = await actor.rollTrait(characterData.rollChoice, { + const result = await actor.rollTrait(data.rollChoice, { skips: { createMessage: true, resources: true, @@ -356,53 +359,40 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat }); if (!result) return; + // todo: move logic to actor.rollTrait() or actor.diceRoll() if (!game.modules.get('dice-so-nice')?.active) foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice }); const rollData = result.messageRoll.toJSON(); delete rollData.options.messageRoll; this.updatePartyData( { - [path]: rollData + [basePath]: { rollData, successful: null } }, this.getUpdatingParts(button) ); } - static async #makeRoll(_event, button) { - const { member } = button.dataset; - const character = this.party.system.groupRoll.aidingCharacters[member]; - this.makeRoll(button, character, `system.groupRoll.aidingCharacters.${member}.rollData`); - } - - static async #makeLeaderRoll(_event, button) { - const character = this.party.system.groupRoll.leader; - this.makeRoll(button, character, 'system.groupRoll.leader.rollData'); - } - - async removeRoll(button, path) { + /** @this GroupRollDialog */ + static async #removeRoll(_event, button) { + const member = button.closest('[data-member-key]').dataset.memberKey; + const { basePath } = this.#getCharacterDataById(member); this.updatePartyData( { - [path]: { + [basePath]: { rollData: null, rollChoice: null, selected: false, - successfull: null + successful: null } }, this.getUpdatingParts(button) ); } - static async #removeRoll(_event, button) { - this.removeRoll(button, `system.groupRoll.aidingCharacters.${button.dataset.member}`); - } - - static async #removeLeaderRoll(_event, button) { - this.removeRoll(button, 'system.groupRoll.leader'); - } - - async rerollDice(button, data, path) { + /** @this GroupRollDialog */ + static async #rerollDice(_, button) { const { diceType } = button.dataset; + const { data, basePath } = this.#getCharacterDataById(button.dataset.member); const dieIndex = diceType === 'hope' ? 0 : diceType === 'fear' ? 1 : 2; const newRoll = game.system.api.dice.DualityRoll.fromData(data.rollData); @@ -416,31 +406,19 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat const rollData = newRoll.toJSON(); this.updatePartyData( { - [path]: rollData + [`${basePath}.rollData`]: rollData }, this.getUpdatingParts(button) ); } - static async #rerollDice(_, button) { - const { member } = button.dataset; - this.rerollDice( - button, - this.party.system.groupRoll.aidingCharacters[member], - `system.groupRoll.aidingCharacters.${member}.rollData` - ); - } - - static async #rerollLeaderDice(_, button) { - this.rerollDice(button, this.party.system.groupRoll.leader, `system.groupRoll.leader.rollData`); - } - - static #markSuccessfull(_event, button) { - const previousValue = this.party.system.groupRoll.aidingCharacters[button.dataset.member].successfull; - const newValue = Boolean(button.dataset.successfull === 'true'); + static #markSuccessful(_event, button) { + const memberKey = button.closest('[data-member-key]').dataset.memberKey; + const previousValue = this.party.system.groupRoll.aidingCharacters[memberKey].successful; + const newValue = Boolean(button.dataset.success === 'true'); this.updatePartyData( { - [`system.groupRoll.aidingCharacters.${button.dataset.member}.successfull`]: + [`system.groupRoll.aidingCharacters.${memberKey}.successful`]: previousValue === newValue ? null : newValue }, this.getUpdatingParts(button) @@ -484,7 +462,7 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat static async #finishRoll() { const totalRoll = this.party.system.groupRoll.leader.roll; for (const character of Object.values(this.party.system.groupRoll.aidingCharacters)) { - totalRoll.terms.push(new foundry.dice.terms.OperatorTerm({ operator: character.successfull ? '+' : '-' })); + totalRoll.terms.push(new foundry.dice.terms.OperatorTerm({ operator: character.successful ? '+' : '-' })); totalRoll.terms.push(new foundry.dice.terms.NumericTerm({ number: 1 })); } diff --git a/module/applications/sheets-configs/setting-feature-config.mjs b/module/applications/sheets-configs/setting-feature-config.mjs index f90bb52f..a5bcc4f9 100644 --- a/module/applications/sheets-configs/setting-feature-config.mjs +++ b/module/applications/sheets-configs/setting-feature-config.mjs @@ -188,8 +188,9 @@ export default class SettingFeatureConfig extends HandlebarsApplicationMixin(App if (type === 'effect') { const move = foundry.utils.getProperty(this.settings, this.movePath); for (const action of move.actions) { - const remainingEffects = action.effects.filter(x => x._id !== id); - if (action.effects.length !== remainingEffects.length) { + const actionEffects = action.effects ?? []; + const remainingEffects = actionEffects.filter(x => x._id !== id); + if (actionEffects.length !== remainingEffects.length) { await action.update({ effects: remainingEffects.map(x => { const { _id, ...rest } = x; diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index c59dd64e..513ad3f3 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -3,7 +3,7 @@ import DhDeathMove from '../../dialogs/deathMove.mjs'; import { CharacterLevelup, LevelupViewMode } from '../../levelup/_module.mjs'; import DhCharacterCreation from '../../characterCreation/characterCreation.mjs'; import FilterMenu from '../../ux/filter-menu.mjs'; -import { getArmorSources, getDocFromElement, getDocFromElementSync } from '../../../helpers/utils.mjs'; +import { getArmorSources, getDocFromElement, getDocFromElementSync, sortBy } from '../../../helpers/utils.mjs'; /**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */ @@ -226,6 +226,11 @@ export default class CharacterSheet extends DHBaseActorSheet { context.resources.stress.emptyPips = context.resources.stress.max < maxResource ? maxResource - context.resources.stress.max : 0; + context.equippedItems = sortBy( + this.document.items.filter(i => i.system.equipped), + i => (i.type === 'weapon' ? (i.system.secondary ? 1 : 0) : 2) + ); + context.beastformActive = this.document.effects.find(x => x.type === 'beastform'); return context; diff --git a/module/applications/sheets/api/application-mixin.mjs b/module/applications/sheets/api/application-mixin.mjs index 5faa5d5c..e941931a 100644 --- a/module/applications/sheets/api/application-mixin.mjs +++ b/module/applications/sheets/api/application-mixin.mjs @@ -725,7 +725,7 @@ export default function DHApplicationMixin(Base) { : null : this.document; - let systemData = {}; + let systemData = null; if (featureOnCharacter) { systemData = { originItemType: this.document.type, @@ -738,10 +738,11 @@ export default function DHApplicationMixin(Base) { const data = { name: cls.defaultName({ type, parent }), - type, - system: systemData + type }; + if (systemData) data.system = systemData; + if (inVault) data['system.inVault'] = true; if (disabled) data.disabled = true; if (type === 'domainCard' && parent?.system.domains?.length) { diff --git a/module/config/itemBrowserConfig.mjs b/module/config/itemBrowserConfig.mjs index 5c0a219b..04b387cb 100644 --- a/module/config/itemBrowserConfig.mjs +++ b/module/config/itemBrowserConfig.mjs @@ -177,8 +177,8 @@ export const typeConfig = { key: 'system.secondary', label: 'DAGGERHEART.UI.ItemBrowser.subtype', choices: [ - { value: false, label: 'DAGGERHEART.ITEMS.Weapon.primaryWeapon' }, - { value: true, label: 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon' } + { value: false, label: 'DAGGERHEART.ITEMS.Weapon.primaryWeapon.full' }, + { value: true, label: 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon.full' } ] }, { diff --git a/module/config/itemConfig.mjs b/module/config/itemConfig.mjs index a3e785c3..43054ec5 100644 --- a/module/config/itemConfig.mjs +++ b/module/config/itemConfig.mjs @@ -453,7 +453,7 @@ export const allArmorFeatures = () => { const feature = homebrewFeatures[key]; const actions = feature.actions.map(action => ({ ...action, - effects: action.effects.map(effect => feature.effects.find(x => x.id === effect._id)), + effects: action.effects?.map(effect => feature.effects.find(x => x.id === effect._id)) ?? [], type: action.type })); const actionEffects = actions.flatMap(a => a.effects); @@ -1407,7 +1407,7 @@ export const allWeaponFeatures = () => { const actions = feature.actions.map(action => ({ ...action, - effects: action.effects.map(effect => feature.effects.find(x => x.id === effect._id)), + effects: action.effects?.map(effect => feature.effects.find(x => x.id === effect._id)) ?? [], type: action.type })); const actionEffects = actions.flatMap(a => a.effects); diff --git a/module/config/resourceConfig.mjs b/module/config/resourceConfig.mjs index 56ef6cd5..d33d7ab3 100644 --- a/module/config/resourceConfig.mjs +++ b/module/config/resourceConfig.mjs @@ -57,15 +57,9 @@ const companionBaseResources = Object.freeze({ stress: { id: 'stress', initial: 0, - max: 0, + max: 3, reverse: true, label: 'DAGGERHEART.GENERAL.stress' - }, - hope: { - id: 'hope', - initial: 0, - reverse: false, - label: 'DAGGERHEART.GENERAL.hope' } }); diff --git a/module/data/actor/adversary.mjs b/module/data/actor/adversary.mjs index d30e090a..d69e17ad 100644 --- a/module/data/actor/adversary.mjs +++ b/module/data/actor/adversary.mjs @@ -189,6 +189,9 @@ export default class DhpAdversary extends DhCreature { prepareDerivedData() { super.prepareDerivedData(); this.attack.roll.isStandardAttack = true; + + // Clamp resources (must be done last to ensure all updates occur) + this.resources.clamp(); } _getTags() { diff --git a/module/data/actor/base.mjs b/module/data/actor/base.mjs index 13ff0a38..9efbe7d7 100644 --- a/module/data/actor/base.mjs +++ b/module/data/actor/base.mjs @@ -1,6 +1,6 @@ import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs'; import DHItem from '../../documents/item.mjs'; -import { getScrollTextData } from '../../helpers/utils.mjs'; +import { createShallowProxy, getScrollTextData } from '../../helpers/utils.mjs'; const fields = foundry.data.fields; @@ -180,8 +180,7 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel { * @returns {object} */ getRollData() { - const data = { ...this }; - return data; + return createShallowProxy(this); } /** diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 1bb3560f..d42f2f64 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -391,8 +391,9 @@ export default class DhCharacter extends DhCreature { return this.domains.map(key => { const domain = allDomainData[key]; return { + id: key, ...domain, - label: game.i18n.localize(domain.label) + label: game.i18n.localize(domain?.label) ?? key }; }); } @@ -410,14 +411,11 @@ export default class DhCharacter extends DhCreature { } get loadoutSlot() { - const loadoutCount = this.domainCards.loadout?.length ?? 0, - worldSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxLoadout, - max = !worldSetting ? null : worldSetting + this.bonuses.maxLoadout; - + const loadoutCount = this.domainCards.loadout?.length ?? 0; + const worldSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxLoadout; return { current: loadoutCount, - available: !max ? true : Math.max(max - loadoutCount, 0), - max + available: loadoutCount < worldSetting }; } @@ -780,6 +778,8 @@ export default class DhCharacter extends DhCreature { prepareDerivedData() { super.prepareDerivedData(); + + this.resources.hope.max -= this.scars; if (this.companion) { for (let levelKey in this.companion.system.levelData.levelups) { const level = this.companion.system.levelData.levelups[levelKey]; @@ -793,7 +793,6 @@ export default class DhCharacter extends DhCreature { } } - this.resources.hope.max -= this.scars; this.attack.roll.trait = this.rules.attack.roll.trait ?? this.attack.roll.trait; this.resources.armor = { @@ -803,6 +802,9 @@ export default class DhCharacter extends DhCreature { }; this.attack.damage.parts.hitPoints.value.custom.formula = `@prof${this.basicAttackDamageDice}${this.rules.attack.damage.bonus ? ` + ${this.rules.attack.damage.bonus}` : ''}`; + + // Clamp resources (must be done last to ensure all updates occur) + this.resources.clamp(); } getRollData() { diff --git a/module/data/actor/companion.mjs b/module/data/actor/companion.mjs index 538031fb..300bd698 100644 --- a/module/data/actor/companion.mjs +++ b/module/data/actor/companion.mjs @@ -144,9 +144,6 @@ export default class DhCompanion extends DhCreature { const level = this.levelData.levelups[levelKey]; for (let selection of level.selections) { switch (selection.type) { - case 'hope': - this.resources.hope += selection.value; - break; case 'vicious': if (selection.data[0] === 'damage') { this.attack.damage.parts.hitPoints.value.dice = adjustDice( @@ -183,6 +180,9 @@ export default class DhCompanion extends DhCreature { return acc; }, this.partner.system.companionData.levelupChoices); } + + // Clamp resources (must be done last to ensure all updates occur) + this.resources.clamp(); } async _preUpdate(changes, options, userId) { diff --git a/module/data/actor/creature.mjs b/module/data/actor/creature.mjs index 88646301..601068ad 100644 --- a/module/data/actor/creature.mjs +++ b/module/data/actor/creature.mjs @@ -60,14 +60,4 @@ export default class DhCreature extends BaseDataActor { } } } - - prepareDerivedData() { - const minLimitResource = resource => { - if (resource) resource.value = Math.min(resource.value, resource.max); - }; - - minLimitResource(this.resources.stress); - minLimitResource(this.resources.hitPoints); - minLimitResource(this.resources.hope); - } } diff --git a/module/data/actor/party.mjs b/module/data/actor/party.mjs index 93596cda..5b9cccab 100644 --- a/module/data/actor/party.mjs +++ b/module/data/actor/party.mjs @@ -18,7 +18,7 @@ export default class DhParty extends BaseDataActor { const fields = foundry.data.fields; return { ...super.defineSchema(), - partyMembers: new ForeignDocumentUUIDArrayField({ type: 'Actor' }, { prune: true }), + partyMembers: new ForeignDocumentUUIDArrayField({ type: 'Actor' }), notes: new fields.HTMLField(), gold: new GoldField(), tagTeam: new fields.EmbeddedDataField(TagTeamData), diff --git a/module/data/fields/actorField.mjs b/module/data/fields/actorField.mjs index d6b58675..a5f6f379 100644 --- a/module/data/fields/actorField.mjs +++ b/module/data/fields/actorField.mjs @@ -80,6 +80,18 @@ class ResourcesField extends fields.TypedObjectField { value.isReversed = resources[key].reverse; value.max = typeof resource.max === 'number' ? (value.max ?? resource.max) : null; } + Object.defineProperty(data, 'clamp', { + value: function () { + for (const key of Object.keys(this)) { + const resource = this[key]; + if (typeof resource?.max === 'number') { + resource.value = Math.clamp(resource.value, 0, resource.max); + } + } + }, + enumerable: false + }); + return data; } diff --git a/module/data/fields/foreignDocumentUUIDArrayField.mjs b/module/data/fields/foreignDocumentUUIDArrayField.mjs index 456c0593..f8969d33 100644 --- a/module/data/fields/foreignDocumentUUIDArrayField.mjs +++ b/module/data/fields/foreignDocumentUUIDArrayField.mjs @@ -10,6 +10,7 @@ export default class ForeignDocumentUUIDArrayField extends foundry.data.fields.A */ constructor(fieldOption = {}, options = {}, context = {}) { super(new ForeignDocumentUUIDField(fieldOption), options, context); + this.options.prune ??= true; } /** @inheritdoc */ diff --git a/module/data/groupRollData.mjs b/module/data/groupRollData.mjs index 78a06b13..10123152 100644 --- a/module/data/groupRollData.mjs +++ b/module/data/groupRollData.mjs @@ -30,7 +30,7 @@ export class CharacterData extends foundry.abstract.DataModel { }), rollData: new fields.JSONField({ nullable: true, initial: null }), selected: new fields.BooleanField({ initial: false }), - successfull: new fields.BooleanField({ nullable: true, initial: null }) + successful: new fields.BooleanField({ nullable: true, initial: null }) }; } diff --git a/module/data/item/base.mjs b/module/data/item/base.mjs index f6c794f1..aebf33bf 100644 --- a/module/data/item/base.mjs +++ b/module/data/item/base.mjs @@ -7,7 +7,12 @@ * @property {boolean} isInventoryItem- Indicates whether items of this type is a Inventory Item */ -import { addLinkedItemsDiff, getScrollTextData, updateLinkedItemApps } from '../../helpers/utils.mjs'; +import { + addLinkedItemsDiff, + getScrollTextData, + createShallowProxy, + updateLinkedItemApps +} from '../../helpers/utils.mjs'; import { ActionsField } from '../fields/actionField.mjs'; import FormulaField from '../fields/formulaField.mjs'; @@ -159,8 +164,8 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { * @returns {object} */ getRollData(options = {}) { - const actorRollData = this.actor?.getRollData() ?? {}; - const data = { ...actorRollData, item: { ...this } }; + const data = this.actor?.getRollData() ?? {}; + data.item = createShallowProxy(this); return data; } diff --git a/module/data/item/weapon.mjs b/module/data/item/weapon.mjs index 75e6dc8e..84e4de7f 100644 --- a/module/data/item/weapon.mjs +++ b/module/data/item/weapon.mjs @@ -28,7 +28,10 @@ export default class DHWeapon extends AttachableItem { equipped: new fields.BooleanField({ initial: false }), //SETTINGS - secondary: new fields.BooleanField({ initial: false, label: 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon' }), + secondary: new fields.BooleanField({ + initial: false, + label: 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon.full' + }), burden: new fields.StringField({ required: true, choices: CONFIG.DH.GENERAL.burden, diff --git a/module/data/scene/scene.mjs b/module/data/scene/scene.mjs index f2a24308..50416573 100644 --- a/module/data/scene/scene.mjs +++ b/module/data/scene/scene.mjs @@ -19,7 +19,7 @@ export default class DHScene extends foundry.abstract.DataModel { close: new fields.NumberField({ integer: true, label: 'DAGGERHEART.CONFIG.Range.close.name' }), far: new fields.NumberField({ integer: true, label: 'DAGGERHEART.CONFIG.Range.far.name' }) }), - sceneEnvironments: new ForeignDocumentUUIDArrayField({ type: 'Actor', prune: true }) + sceneEnvironments: new ForeignDocumentUUIDArrayField({ type: 'Actor' }) }; } } diff --git a/module/data/settings/Homebrew.mjs b/module/data/settings/Homebrew.mjs index d4b7b03f..b5e02675 100644 --- a/module/data/settings/Homebrew.mjs +++ b/module/data/settings/Homebrew.mjs @@ -54,7 +54,7 @@ export default class DhHomebrew extends foundry.abstract.DataModel { maxDomains: new fields.NumberField({ required: true, integer: true, - min: 1, + min: 0, initial: 2, label: 'DAGGERHEART.SETTINGS.Homebrew.FIELDS.maxDomains.label' }), @@ -196,6 +196,12 @@ export default class DhHomebrew extends foundry.abstract.DataModel { return source; } + _initialize(options) { + super._initialize(options); + this.maxDomains ||= Infinity; + this.maxLoadout ||= Infinity; + } + /** Invoked by the setting when data changes */ handleChange() { if (this.maxFear) { diff --git a/module/documents/activeEffect.mjs b/module/documents/activeEffect.mjs index 227e2613..08463818 100644 --- a/module/documents/activeEffect.mjs +++ b/module/documents/activeEffect.mjs @@ -169,27 +169,36 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { super._applyChangeUnguided(actor, change, changes, options); } + /** Recursively finds the first parent document of the given object */ + static #resolveParentDocument(model, documentClass) { + return model instanceof documentClass + ? model + : model.parent + ? this.#resolveParentDocument(model.parent, documentClass) + : null; + } + static getChangeValue(model, change, effect) { - let key = change.value.toString(); - const isOriginTarget = key.toLowerCase().includes('origin.@'); - let parseModel = model; - if (isOriginTarget && effect.origin) { - key = change.key.replaceAll(/origin\.@/gi, '@'); - try { - const originEffect = foundry.utils.fromUuidSync(effect.origin); - const doc = - originEffect.parent?.parent instanceof game.system.api.documents.DhpActor - ? originEffect.parent - : originEffect.parent.parent; - if (doc) parseModel = doc; - } catch (_) {} + let value = change.value.toString(); + const useOrigin = value.toLowerCase().includes('origin.@') && effect.origin; + let origin = null; + if (effect.origin) { + if (useOrigin) value = value.replaceAll(/origin\.@/gi, '@'); + const originEffect = foundry.utils.fromUuidSync(effect.origin); + origin = this.#resolveParentDocument(originEffect, Item); } + // Get the actor and item documents. Note that actor roll data is inclusive of system roll data + const actor = this.#resolveParentDocument(model, Actor); + const item = + (useOrigin ? origin : null) ?? + this.#resolveParentDocument(effect.parent, Item) ?? + (origin?.actor === actor ? origin : null); const stackingParsedValue = effect.system.stacking - ? Roll.replaceFormulaData(key, { stacks: effect.system.stacking.value }) - : key; - const evalValue = itemAbleRollParse(stackingParsedValue, parseModel, effect.parent); - return evalValue ?? key; + ? Roll.replaceFormulaData(value, { stacks: effect.system.stacking.value }) + : value; + const evalValue = this.effectSafeEval(itemAbleRollParse(stackingParsedValue, actor, item)); + return evalValue ?? value; } /** diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index db249033..eb57a186 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -1,7 +1,7 @@ import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs'; import { LevelOptionType } from '../data/levelTier.mjs'; import DHFeature from '../data/item/feature.mjs'; -import { createScrollText, damageKeyToNumber, getDamageKey } from '../helpers/utils.mjs'; +import { createScrollText, damageKeyToNumber, getDamageKey, createShallowProxy } from '../helpers/utils.mjs'; import DhCompanionLevelUp from '../applications/levelup/companionLevelup.mjs'; import { ResourceUpdateMap } from '../data/action/baseAction.mjs'; import { abilities } from '../config/actorConfig.mjs'; @@ -99,7 +99,7 @@ export default class DhpActor extends Actor { } // Configure prototype token settings - if (['character', 'companion', 'party'].includes(this.type)) + if (['character', 'companion', 'party'].includes(this.type)) { Object.assign(update, { prototypeToken: { sight: { enabled: true }, @@ -107,6 +107,8 @@ export default class DhpActor extends Actor { disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY } }); + } + this.updateSource(update); } @@ -593,10 +595,7 @@ export default class DhpActor extends Actor { /**@inheritdoc */ getRollData() { - const rollData = foundry.utils.deepClone(super.getRollData()); - /* system gets repeated infinately which causes issues when trying to use the data for document creation */ - delete rollData.system; - + const rollData = createShallowProxy(super.getRollData()); rollData.id = this.id; rollData.name = this.name; rollData.system = this.system.getRollData(); diff --git a/module/documents/item.mjs b/module/documents/item.mjs index 8ece56fa..93aa3b28 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -54,13 +54,7 @@ export default class DHItem extends foundry.documents.Item { * @returns */ getRollData(options = {}) { - let data; - if (this.system.getRollData) data = this.system.getRollData(options); - else { - const actorRollData = this.actor?.getRollData(options) ?? {}; - data = { ...actorRollData, item: { ...this.system } }; - } - + let data = this.system.getRollData(options); if (data?.item) { data.item.flags = { ...this.flags }; data.item.name = this.name; diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index 4527da1a..1650b505 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -189,17 +189,14 @@ export const getDeleteKeys = (property, innerProperty, innerPropertyDefaultValue // Fix on Foundry native formula replacement for DH const nativeReplaceFormulaData = Roll.replaceFormulaData; -Roll.replaceFormulaData = function (formula, baseData = {}, { missing, warn = false } = {}) { +Roll.replaceFormulaData = function (formula, data = {}, { missing, warn = false } = {}) { /* Inserting global data */ - const data = { - ...baseData, - partySize: game.actors?.party?.system.partyMembers.length ?? 0 - }; + const defaultingTypes = [ + ...Object.keys(CONFIG.DH.GENERAL.multiplierTypes).map(x => ({ term: x, default: 1 })), + { term: 'partySize', default: game.actors?.party?.system.partyMembers.length ?? 0 } + ]; - const terms = Object.keys(CONFIG.DH.GENERAL.multiplierTypes).map(type => { - return { term: type, default: 1 }; - }); - formula = terms.reduce((a, c) => a.replaceAll(`@${c.term}`, data[c.term] ?? c.default), formula); + formula = defaultingTypes.reduce((a, c) => a.replaceAll(`@${c.term}`, data[c.term] ?? c.default), formula); return nativeReplaceFormulaData(formula, data, { missing, warn }); }; @@ -375,10 +372,11 @@ export const itemAbleRollParse = (value, actor, item) => { const isItemTarget = value.toLowerCase().includes('item.@'); const slicedValue = isItemTarget ? value.replaceAll(/item\.@/gi, '@') : value; - const model = isItemTarget ? item : actor; + const model = isItemTarget || item instanceof Item ? item : actor; + const rollData = isItemTarget || !model?.getRollData ? model : model.getRollData(); try { - return Roll.replaceFormulaData(slicedValue, isItemTarget || !model?.getRollData ? model : model.getRollData()); + return Roll.replaceFormulaData(slicedValue, rollData); } catch (_) { return ''; } @@ -812,3 +810,31 @@ export function sortBy(arr, fn) { }; return arr.sort(cmp); } + +/** + * Creates a proxy that allows retrieval of top data but diverts updates to a different object. + * Generally used for roll data + */ +export function createShallowProxy(obj) { + if (obj._isShallowProxy) return obj; + + const overrides = {}; + return new Proxy(obj, { + get(target, prop, receiver) { + if (prop === '_isShallowProxy') return true; + if (prop in overrides) return overrides[prop]; + return Reflect.get(target, prop, receiver); + }, + set(_target, prop, newValue) { + overrides[prop] = newValue; + return true; + }, + deleteProperty(_target, prop) { + delete overrides[prop]; + return true; + }, + has(target, key) { + return key in overrides || key in target; + } + }); +} diff --git a/package-lock.json b/package-lock.json index b8fef1cd..47c5dede 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,8 +19,8 @@ "eslint": "^10.2.1", "eslint-plugin-prettier": "^5.5.5", "globals": "^17.5.0", - "husky": "^9.1.5", - "lint-staged": "^15.2.10", + "husky": "^9.1.7", + "lint-staged": "^16.4.0", "postcss": "^8.4.32", "prettier": "^3.5.3", "rollup-plugin-postcss": "^4.0.2" @@ -752,10 +752,11 @@ } }, "node_modules/ansi-escapes": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", - "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", "dev": true, + "license": "MIT", "dependencies": { "environment": "^1.0.0" }, @@ -767,10 +768,11 @@ } }, "node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -779,10 +781,11 @@ } }, "node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -1207,6 +1210,7 @@ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, + "license": "MIT", "dependencies": { "restore-cursor": "^5.0.0" }, @@ -1218,39 +1222,34 @@ } }, "node_modules/cli-truncate": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", - "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", + "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", "dev": true, + "license": "MIT", "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^7.0.0" + "slice-ansi": "^8.0.0", + "string-width": "^8.2.0" }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-truncate/node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true - }, "node_modules/cli-truncate/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", + "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", "dev": true, + "license": "MIT", "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1357,15 +1356,17 @@ "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/commander": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", - "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20" } }, "node_modules/commondir": { @@ -1854,6 +1855,7 @@ "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -2175,33 +2177,11 @@ } }, "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true - }, - "node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } + "license": "MIT" }, "node_modules/expand-tilde": { "version": "2.0.2", @@ -2471,10 +2451,11 @@ } }, "node_modules/get-east-asian-width": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", - "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", + "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -2519,18 +2500,6 @@ "node": ">= 0.4" } }, - "node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -2931,20 +2900,12 @@ "node": ">=0.10.0" } }, - "node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "engines": { - "node": ">=16.17.0" - } - }, "node_modules/husky": { "version": "9.1.7", "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", "dev": true, + "license": "MIT", "bin": { "husky": "bin.js" }, @@ -3213,12 +3174,16 @@ } }, "node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3321,18 +3286,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-typed-array": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", @@ -3545,52 +3498,38 @@ "node": ">=10.13.0" } }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, "node_modules/lint-staged": { - "version": "15.5.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.2.tgz", - "integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==", + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.4.0.tgz", + "integrity": "sha512-lBWt8hujh/Cjysw5GYVmZpFHXDCgZzhrOm8vbcUdobADZNOK/bRshr2kM3DfgrrtR1DQhfupW9gnIXOfiFi+bw==", "dev": true, + "license": "MIT", "dependencies": { - "chalk": "^5.4.1", - "commander": "^13.1.0", - "debug": "^4.4.0", - "execa": "^8.0.1", - "lilconfig": "^3.1.3", - "listr2": "^8.2.5", - "micromatch": "^4.0.8", - "pidtree": "^0.6.0", + "commander": "^14.0.3", + "listr2": "^9.0.5", + "picomatch": "^4.0.3", "string-argv": "^0.3.2", - "yaml": "^2.7.0" + "tinyexec": "^1.0.4", + "yaml": "^2.8.2" }, "bin": { "lint-staged": "bin/lint-staged.js" }, "engines": { - "node": ">=18.12.0" + "node": ">=20.17" }, "funding": { "url": "https://opencollective.com/lint-staged" } }, "node_modules/listr2": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", - "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", "dev": true, + "license": "MIT", "dependencies": { - "cli-truncate": "^4.0.0", + "cli-truncate": "^5.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.1.0", @@ -3598,7 +3537,7 @@ "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } }, "node_modules/loader-utils": { @@ -3664,6 +3603,7 @@ "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, + "license": "MIT", "dependencies": { "ansi-escapes": "^7.0.0", "cli-cursor": "^5.0.0", @@ -3678,26 +3618,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/is-fullwidth-code-point": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", - "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", - "dev": true, - "dependencies": { - "get-east-asian-width": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/log-update/node_modules/slice-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", - "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" @@ -3766,12 +3692,6 @@ "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", "dev": true }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -3807,23 +3727,12 @@ "node": ">=4" } }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/mimic-function": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -3985,33 +3894,6 @@ "node": ">= 10.13.0" } }, - "node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -4066,15 +3948,16 @@ } }, "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", "dev": true, + "license": "MIT", "dependencies": { - "mimic-fn": "^4.0.0" + "mimic-function": "^5.0.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4259,10 +4142,11 @@ "dev": true }, "node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -4270,18 +4154,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", - "dev": true, - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -5169,6 +5041,7 @@ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, + "license": "MIT", "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" @@ -5180,21 +5053,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/restore-cursor/node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "dev": true, - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -5208,7 +5066,8 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/rollup": { "version": "4.44.0", @@ -5488,6 +5347,7 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { "node": ">=14" }, @@ -5496,16 +5356,17 @@ } }, "node_modules/slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", + "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" + "ansi-styles": "^6.2.3", + "is-fullwidth-code-point": "^5.1.0" }, "engines": { - "node": ">=12" + "node": ">=20" }, "funding": { "url": "https://github.com/chalk/slice-ansi?sponsor=1" @@ -5639,12 +5500,13 @@ } }, "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-regex": "^6.2.2" }, "engines": { "node": ">=12" @@ -5653,18 +5515,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/style-inject": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/style-inject/-/style-inject-0.3.0.tgz", @@ -5800,6 +5650,16 @@ "readable-stream": "3" } }, + "node_modules/tinyexec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", + "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -6082,10 +5942,11 @@ } }, "node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", @@ -6099,16 +5960,18 @@ } }, "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" }, "node_modules/wrap-ansi/node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", @@ -6135,15 +5998,19 @@ } }, "node_modules/yaml": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", - "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "dev": true, + "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yargs": { diff --git a/package.json b/package.json index 28c83549..52bb4ce7 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ "createSymlink": "node ./tools/create-symlink.mjs", "setup:dev": "node ./tools/dev-setup.mjs", "lint": "eslint", - "lint:fix": "eslint --fix" + "lint:fix": "eslint --fix", + "prepare": "husky" }, "devDependencies": { "@foundryvtt/foundryvtt-cli": "^1.0.2", @@ -29,13 +30,13 @@ "eslint": "^10.2.1", "eslint-plugin-prettier": "^5.5.5", "globals": "^17.5.0", - "husky": "^9.1.5", - "lint-staged": "^15.2.10", + "husky": "^9.1.7", + "lint-staged": "^16.4.0", "postcss": "^8.4.32", "prettier": "^3.5.3", "rollup-plugin-postcss": "^4.0.2" }, "lint-staged": { - "**/*": "prettier --write --ignore-unknown" + "**/*": "eslint --fix" } } diff --git a/styles/less/dialog/group-roll-dialog/_common.less b/styles/less/dialog/group-roll-dialog/_common.less new file mode 100644 index 00000000..41573718 --- /dev/null +++ b/styles/less/dialog/group-roll-dialog/_common.less @@ -0,0 +1,46 @@ +h1 { + color: light-dark(@dark-blue, @golden); + font-family: var(--dh-font-subtitle); + font-size: var(--font-size-24); + text-align: center; + font-weight: 700; +} + +header { + --bar-color: light-dark(@dark-blue, @golden); + color: light-dark(@dark, @beige); + display: flex; + justify-content: center; + align-items: center; + + &:not(:first-child) { + margin-top: var(--spacer-8); + } + + span { + padding: 0 10px; + } + + &:before { + content: ' '; + flex: 1; + height: 1px; + background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, var(--bar-color) 100%); + } + + &:after { + content: ' '; + flex: 1; + height: 1px; + background: linear-gradient(90deg, var(--bar-color) 0%, rgba(0, 0, 0, 0) 100%); + } +} + +img.portrait { + border-radius: 50%; + border: none; + object-fit: cover; + object-position: center top; + width: 2.5rem; + height: 2.5rem; +} diff --git a/styles/less/dialog/group-roll-dialog/index.less b/styles/less/dialog/group-roll-dialog/index.less new file mode 100644 index 00000000..27925fa2 --- /dev/null +++ b/styles/less/dialog/group-roll-dialog/index.less @@ -0,0 +1,8 @@ +.daggerheart.dialog.dh-style.views.group-roll-dialog { + .window-content { + @import "./_common.less"; + } +} + +@import "./initialization.less"; +@import "./main.less"; diff --git a/styles/less/dialog/group-roll-dialog/initialization.less b/styles/less/dialog/group-roll-dialog/initialization.less index b2e7e021..b32f4756 100644 --- a/styles/less/dialog/group-roll-dialog/initialization.less +++ b/styles/less/dialog/group-roll-dialog/initialization.less @@ -1,62 +1,59 @@ -.theme-light .daggerheart.dialog.dh-style.views.group-roll-dialog { - .initialization-container .members-container .member-container { - .member-name { - background-image: url('../assets/parchments/dh-parchment-light.png'); - } - } -} - .daggerheart.dialog.dh-style.views.group-roll-dialog { - .initialization-container { - h2 { - text-align: center; - } - - .members-container { - display: grid; - grid-template-columns: 1fr 1fr 1fr 1fr; - gap: 8px; - - .member-container { - position: relative; - display: flex; - justify-content: center; - - &.inactive { - opacity: 0.4; - } - - .member-name { - position: absolute; - padding: 0 2px; - border: 1px solid; - border-radius: 6px; - margin-top: 4px; - color: light-dark(@dark, @beige); - background-image: url('../assets/parchments/dh-parchment-dark.png'); - text-align: center; - } - - img { - border-radius: 6px; - border: 1px solid light-dark(@dark-blue, @golden); - } - } - } + .initialization-container.active { + display: flex; + flex-direction: column; + overflow: hidden; .main-roll { - margin-top: 8px; - display: grid; - grid-template-columns: 1fr 1fr; - gap: 8px; + display: flex; + flex-direction: column; + text-align: center; + padding-bottom: 4px; &.inactive { opacity: 0.4; } } + .hint { + color: var(--color-form-hint); + line-height: 1; + padding: var(--spacer-8) 0; + font-family: var(--dh-font-body); + font-size: var(--font-size-12); + font-weight: 300; + } + + .members-container { + display: flex; + flex-direction: column; + gap: 8px; + overflow-y: auto; + + .member-container { + display: flex; + position: relative; + justify-content: center; + height: unset; + padding: 4px 8px; + gap: var(--spacer-8); + flex: 0 0 auto; + + &:not(.inactive) { + background: @golden-bg; + } + + .name { + flex: 1; + color: light-dark(@dark, @beige); + font-weight: 500; + text-align: left; + } + } + } + footer { - margin-top: 8px; + margin-top: 12px; display: flex; gap: 8px; diff --git a/styles/less/dialog/group-roll-dialog/leader.less b/styles/less/dialog/group-roll-dialog/leader.less deleted file mode 100644 index b3fa3a3b..00000000 --- a/styles/less/dialog/group-roll-dialog/leader.less +++ /dev/null @@ -1,35 +0,0 @@ -.daggerheart.dialog.dh-style.views.group-roll-dialog { - .main-character-outer-container { - &.inactive { - opacity: 0.3; - pointer-events: none; - } - - .main-character-container { - .character-info { - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - height: 64px; - - img { - height: 64px; - border-radius: 6px; - border: 1px solid light-dark(@dark-blue, @golden); - } - - .character-data { - padding-left: 0.75rem; - flex: 1; - height: 100%; - display: flex; - flex-direction: column; - justify-content: space-between; - text-align: left; - font-size: var(--font-size-18); - } - } - } - } -} diff --git a/styles/less/dialog/group-roll-dialog/main.less b/styles/less/dialog/group-roll-dialog/main.less new file mode 100644 index 00000000..f266dcc7 --- /dev/null +++ b/styles/less/dialog/group-roll-dialog/main.less @@ -0,0 +1,273 @@ +.daggerheart.dialog.dh-style.views.group-roll-dialog { + .group-roll.active { + display: flex; + flex-direction: column; + overflow: hidden; + + a.roll-button { + &:hover { + text-shadow: none; + filter: drop-shadow(0 0 3px @golden-90); + } + } + + .aiding-members { + display: flex; + flex-direction: column; + gap: 6px; + overflow-y: auto; + } + + .item-tags { + gap: 6px; + .tag.failure, + .tag.success { + font-weight: 600; + justify-content: center; + min-width: 3ch; + } + + .tag.success { + border-color: @green; + background: @green-10; + color: @green; + } + + .tag.failure { + border-color: @red; + background: @red-10; + color: @red; + } + + .tag { + padding-top: 0; + padding-bottom: 0; + line-height: 1.1875rem; + } + } + + .with-result { + border-radius: 5px; + background: var(--duality-bg); + color: var(--color-light-2); + + &.hope { + --duality-text-color: @golden; + --duality-bg: url(../assets/parchments/dh-parchment-hope.png); + } + + &.fear { + --duality-text-color: @chat-blue; + --duality-bg: url(../assets/parchments/dh-parchment-fear.png); + } + + &.critical { + --duality-text-color: @chat-purple; + --duality-bg: url(../assets/parchments/dh-parchment-critical.png); + } + + .duality-label { + font-family: var(--dh-font-subtitle); + color: var(--duality-text-color); + font-weight: 700; + } + } + + .member-roll-container { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + min-height: 3.375rem; + + &.inactive { + pointer-events: none; + } + + .name-area { + display: flex; + flex-direction: column; + flex: 1; + justify-content: center; + .name { + font-weight: 500; + } + .trait { + display: flex; + align-items: center; + gap: 6px; + select { + --input-height: 2em; + width: auto; + } + } + .item-tags { + align-items: stretch; + } + } + + .buttons { + display: flex; + flex-direction: row; + button { + --button-text-color: var(--color-text-primary); + --button-size: 1.5em; + padding: 0 var(--spacer-4); + img { + width: 100%; + height: 100%; + object-fit: contain; + } + } + } + + a.roll-button.initial-roll { + width: 1.875rem; + height: 1.875rem; + margin-right: 2px; /** makes hover look a bit nicer */ + } + + .with-result { + display: flex; + justify-content: end; + align-items: center; + gap: 6px; + + .roll-data { + display: flex; + flex-direction: column; + align-items: end; + justify-content: center; + padding: 0 4px; + min-height: 3rem; + + .duality-label { + font-size: var(--font-size-15); + + .unused-damage { + text-decoration: line-through; + } + + .with { + font-size: var(--font-size-10); + } + } + + .roll-dice-container { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + gap: 2px; + + .roll-dice { + position: relative; + display: flex; + align-items: center; + justify-content: center; + + .dice-label { + position: absolute; + color: white; + font-size: 1rem; + paint-order: stroke fill; + -webkit-text-stroke: 2px black; + } + + img { + height: 1.3125rem; + } + } + + .roll-operator { + font-size: var(--font-size-18); + padding: 0 1px; + } + + .roll-value { + font-size: var(--font-size-16); + padding: 0 1px; + } + } + } + + .buttons { + flex-direction: column; + button { + color: var(--medium-red); + &[data-success=true] { + color: var(--green); + } + &.active { + text-shadow: 0 0 1px light-dark(@dark-80, @beige-80); + } + &.inactive { + opacity: 0.35; + } + } + } + } + } + } + + .group-roll-results { + display: flex; + flex-direction: column; + align-items: stretch; + gap: 4px; + font-size: var(--font-size-12); + padding: 6px 12px; + margin-top: 8px; + + &.empty { + color: light-dark(@dark-blue-90, @beige-80); + border-radius: 3px; + justify-content: center; + border: 1px dashed light-dark(@dark-blue-90, @beige-80); + text-align: center; + height: 3.25rem; + font-family: @font-body; + } + + .row { + display: flex; + align-items: center; + justify-content: space-between; + } + + .divider { + height: 1px; + background-image: linear-gradient(90deg, transparent 0%, var(--duality-text-color) 50%, transparent 100%); + margin-block: var(--spacer-4); + } + + .modifiers .item-tags { + min-height: calc(2px + 1.1875rem); + } + + .total { + .label { + font-size: var(--font-size-14); + } + .duality-label { + display: flex; + align-items: center; + gap: var(--spacer-4); + .value { + font-size: 20px; + } + } + } + } + + .finish-container { + margin-top: 16px; + gap: 16px; + display: grid; + grid-template-columns: 1fr 1fr 1fr; + + .finish-button { + grid-column: span 2; + } + } +} diff --git a/styles/less/dialog/group-roll-dialog/sheet.less b/styles/less/dialog/group-roll-dialog/sheet.less deleted file mode 100644 index 70afc1fe..00000000 --- a/styles/less/dialog/group-roll-dialog/sheet.less +++ /dev/null @@ -1,265 +0,0 @@ -.daggerheart.dialog.dh-style.views.group-roll-dialog { - .team-container { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 16px; - margin-bottom: 16px; - - .team-member-container { - display: flex; - flex-direction: column; - justify-content: space-between; - gap: 8px; - flex: 1; - - &.inactive { - opacity: 0.3; - pointer-events: none; - } - - .data-container { - display: flex; - flex-direction: column; - gap: 8px; - width: 100%; - } - - .member-info { - display: flex; - align-items: start; - width: 100%; - - img { - height: 64px; - border-radius: 6px; - border: 1px solid light-dark(@dark-blue, @golden); - } - - .member-data { - padding-left: 0.75rem; - flex: 1; - height: 100%; - display: flex; - flex-direction: column; - justify-content: space-between; - text-align: left; - font-size: var(--font-size-18); - } - } - } - } - - .roll-container { - display: flex; - flex-direction: column; - } - - .roll-title { - font-size: var(--font-size-20); - font-weight: bold; - color: light-dark(@dark-blue, @golden); - text-align: center; - display: flex; - align-items: center; - gap: 8px; - - &.hope, - &.fear, - &.critical { - color: var(--text-color); - } - - &.hope { - --text-color: @golden; - } - - &.fear { - --text-color: @chat-blue; - } - - &.critical { - --text-color: @chat-purple; - } - - &::before, - &::after { - color: var(--text-color); - content: ''; - flex: 1; - height: 2px; - } - - &::before { - background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, light-dark(@dark-blue, @golden) 100%); - } - - &::after { - background: linear-gradient(90deg, light-dark(@dark-blue, @golden) 0%, rgba(0, 0, 0, 0) 100%); - } - } - - .roll-tools { - display: flex; - gap: 4px; - align-items: center; - - img { - height: 16px; - } - - a { - display: flex; - font-size: 16px; - - &:hover { - text-shadow: none; - filter: drop-shadow(0 0 8px var(--golden)); - } - } - } - - .roll-data { - display: flex; - flex-direction: column; - align-items: center; - gap: 4px; - - &.hope { - --text-color: @golden; - --bg-color: @golden-40; - } - - &.fear { - --text-color: @chat-blue; - --bg-color: @chat-blue-40; - } - - &.critical { - --text-color: @chat-purple; - --bg-color: @chat-purple-40; - } - - .duality-label { - color: var(--text-color); - font-size: var(--font-size-20); - font-weight: bold; - text-align: center; - - .unused-damage { - text-decoration: line-through; - } - } - - .roll-dice-container { - display: flex; - align-items: center; - justify-content: center; - flex-wrap: wrap; - gap: 8px; - - .roll-dice { - position: relative; - display: flex; - align-items: center; - justify-content: center; - - .dice-label { - position: absolute; - color: white; - font-size: 1rem; - paint-order: stroke fill; - -webkit-text-stroke: 2px black; - } - - img { - height: 32px; - } - } - - .roll-operator { - font-size: var(--font-size-24); - } - - .roll-value { - font-size: 18px; - } - } - - .roll-total { - background: var(--bg-color); - color: var(--text-color); - border-radius: 4px; - padding: 3px; - } - } - - .roll-success-container { - display: flex; - align-items: center; - justify-content: space-around; - - .roll-success-tools { - display: flex; - align-items: center; - gap: 4px; - color: light-dark(@dark-blue, @golden); - - i { - font-size: 24px; - } - } - - .roll-success-modifier { - display: flex; - align-items: center; - justify-content: right; - gap: 2px; - font-size: var(--font-size-20); - padding: 0px 4px; - - &.success { - background: @green-10; - color: @green; - } - - &.failure { - background: @red-10; - color: @red; - } - } - } - - .section-title { - font-size: var(--font-size-18); - font-weight: bold; - } - - .group-roll-results { - display: flex; - flex-direction: column; - align-items: center; - gap: 4px; - font-size: var(--font-size-20); - - .group-roll-container { - display: flex; - align-items: center; - gap: 2px; - } - } - - .finish-container { - margin-top: 16px; - gap: 16px; - display: grid; - grid-template-columns: 1fr 1fr 1fr; - - .finish-button { - grid-column: span 2; - } - } - - .hint { - text-align: center; - } -} diff --git a/styles/less/dialog/group-roll/group-roll.less b/styles/less/dialog/group-roll/group-roll.less deleted file mode 100644 index f2895d31..00000000 --- a/styles/less/dialog/group-roll/group-roll.less +++ /dev/null @@ -1,50 +0,0 @@ -@import '../../utils/colors.less'; - -.application.daggerheart.group-roll { - fieldset.one-column { - min-width: 500px; - margin-bottom: 10px; - } - .actor-item { - display: flex; - align-items: center; - gap: 15px; - width: 100%; - - img { - height: 40px; - width: 40px; - border-radius: 50%; - object-fit: cover; - } - - .actor-info { - display: flex; - flex-direction: column; - gap: 10px; - - .actor-check-info { - display: flex; - gap: 10px; - - .form-fields { - display: flex; - gap: 5px; - align-items: center; - - input { - max-width: 40px; - text-align: center; - } - } - } - } - - .controls { - margin-left: auto; - } - } - .tooltip-container { - width: 100%; - } -} diff --git a/styles/less/dialog/index.less b/styles/less/dialog/index.less index 947142ff..eb882eeb 100644 --- a/styles/less/dialog/index.less +++ b/styles/less/dialog/index.less @@ -31,14 +31,10 @@ @import './reroll-dialog/sheet.less'; -@import './group-roll/group-roll.less'; - @import './tag-team-dialog/initialization.less'; @import './tag-team-dialog/sheet.less'; -@import './group-roll-dialog/initialization.less'; -@import './group-roll-dialog/leader.less'; -@import './group-roll-dialog/sheet.less'; +@import './group-roll-dialog/index.less'; @import './image-select/sheet.less'; diff --git a/styles/less/global/elements.less b/styles/less/global/elements.less index c5bca1da..afd56057 100755 --- a/styles/less/global/elements.less +++ b/styles/less/global/elements.less @@ -100,7 +100,7 @@ scrollbar-color: light-dark(@dark-blue, @golden) transparent; } - button { + button:where(:not(.plain)) { background: light-dark(transparent, @golden); border: 1px solid light-dark(@dark-blue, @dark-blue); color: light-dark(@dark-blue, @dark-blue); diff --git a/system.json b/system.json index 6751f957..9b8a8403 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "id": "daggerheart", "title": "Daggerheart", "description": "An unofficial implementation of the Daggerheart system", - "version": "2.2.0", + "version": "2.2.1", "compatibility": { "minimum": "14.359", "verified": "14.360", @@ -10,7 +10,7 @@ }, "url": "https://github.com/Foundryborne/daggerheart", "manifest": "https://raw.githubusercontent.com/Foundryborne/daggerheart/v14/system.json", - "download": "https://github.com/Foundryborne/daggerheart/releases/download/2.2.0/system.zip", + "download": "https://github.com/Foundryborne/daggerheart/releases/download/2.2.1/system.zip", "authors": [ { "name": "WBHarry" diff --git a/templates/dialogs/group-roll/group-roll.hbs b/templates/dialogs/group-roll/group-roll.hbs deleted file mode 100644 index 9b23c0a5..00000000 --- a/templates/dialogs/group-roll/group-roll.hbs +++ /dev/null @@ -1,84 +0,0 @@ -
-
-

{{localize "DAGGERHEART.UI.Chat.groupRoll.title"}}

-
- -
- {{localize "DAGGERHEART.UI.Chat.groupRoll.leader"}} - {{#unless leader.actor}} - -
- {{localize "DAGGERHEART.UI.Chat.groupRoll.selectLeader"}} -
- {{else}} -
- {{leader.actor.name}} -
- {{leader.actor.name}} -
-
- - -
- {{!-- Not used yet --}} - {{!--
- - -
--}} -
-
-
- - - -
-
- {{/unless}} -
- -
- {{localize "DAGGERHEART.UI.Chat.groupRoll.partyTeam"}} - - - - {{#if (gt this.members.length 0)}} - {{#each members as |member index|}} -
- {{member.actor.name}} -
- {{member.actor.name}} -
-
- - -
- {{!-- Not used yet --}} - {{!--
- - -
--}} -
-
-
- - - -
-
- {{/each}} - {{/if}} - {{#unless allSelected}} -
- {{localize "DAGGERHEART.UI.Chat.groupRoll.selectMember"}} -
- {{/unless}} -
- -
\ No newline at end of file diff --git a/templates/dialogs/groupRollDialog/groupRoll.hbs b/templates/dialogs/groupRollDialog/groupRoll.hbs deleted file mode 100644 index edf1c980..00000000 --- a/templates/dialogs/groupRollDialog/groupRoll.hbs +++ /dev/null @@ -1,20 +0,0 @@ -
-
- {{localize "DAGGERHEART.GENERAL.result.single"}} - -
- {{#if hasRolled}}{{groupRoll.total}} {{groupRoll.totalLabel}}{{/if}} -
- {{#if groupRoll.leaderTotal includeZero=true}}{{groupRoll.leaderTotal}}{{else}}{{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.leaderRoll"}}{{/if}} - {{#each groupRoll.modifiers as |modifier|}} - {{#if (gte modifier 0)}}+{{else}}-{{/if}} - {{positive modifier}} - {{/each}} - {{#unless groupRoll.modifiers.length}} - + - {{localize "DAGGERHEART.GENERAL.Modifier.plural"}} - {{/unless}} -
-
-
-
\ No newline at end of file diff --git a/templates/dialogs/groupRollDialog/groupRollMember.hbs b/templates/dialogs/groupRollDialog/groupRollMember.hbs deleted file mode 100644 index acf8e8f1..00000000 --- a/templates/dialogs/groupRollDialog/groupRollMember.hbs +++ /dev/null @@ -1,85 +0,0 @@ -{{#with (lookup members partId)}} -
-
-
- -
- {{name}} -
-
-
- {{!-- --}} - -
-
-
-
-
- {{#if readyToRoll}} -
- - {{localize "DAGGERHEART.GENERAL.roll"}} -
- - - - - {{#if hasRolled}} - - - - {{/if}} -
-
- - {{#if roll}} -
-
{{roll.total}} {{localize "DAGGERHEART.GENERAL.withThing" thing=roll.totalLabel}}
-
- - {{roll.dHope.total}} - - - + - - {{roll.dFear.total}} - - - {{#if roll.advantage.type}} - {{#if (eq roll.advantage.type 1)}}+{{else}}-{{/if}} - - {{roll.advantage.value}} - - - {{/if}} - {{#if (gte roll.modifierTotal 0)}}+{{else}}-{{/if}} - {{positive roll.modifierTotal}} -
-
- {{else}} - {{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.makeYourRoll"}} - {{/if}} -
- {{/if}} - {{#if hasRolled}} -
- {{#if ../isGM}} - - {{/if}} -
- {{localize "DAGGERHEART.GENERAL.Modifier.single"}}{{#if successfull}} + 1{{else if (isNullish successfull)}} + ?{{else}} - 1{{/if}} -
-
- {{/if}} -
-
-{{/with}} \ No newline at end of file diff --git a/templates/dialogs/groupRollDialog/initialization.hbs b/templates/dialogs/groupRollDialog/initialization.hbs index a520b8bd..a01a00bb 100644 --- a/templates/dialogs/groupRollDialog/initialization.hbs +++ b/templates/dialogs/groupRollDialog/initialization.hbs @@ -1,32 +1,43 @@
+

{{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.initializationTitle"}}

+
{{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.leader"}}
+
+
{{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.selectLeaderHint"}}
+ +
+ +
{{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.members"}}
+
{{"DAGGERHEART.APPLICATIONS.GroupRollSelect.selectParticipantsHint"}}
{{#each memberSelection as |member|}} - - {{member.name}} - - + + + {{member.name}} + {{#if (eq @root.selectedLeader.memberId member.id)}} + + {{/if}} + + + {{/each}}
-
-
- -
- -
-
-
-
\ No newline at end of file diff --git a/templates/dialogs/groupRollDialog/leader.hbs b/templates/dialogs/groupRollDialog/leader.hbs deleted file mode 100644 index 3d5db3f7..00000000 --- a/templates/dialogs/groupRollDialog/leader.hbs +++ /dev/null @@ -1,73 +0,0 @@ -
- {{#with leader}} -
-
{{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.leader"}}
-
-
-
- -
- {{name}} -
-
-
- -
-
-
-
-
-
- - {{#if readyToRoll}} -
- - {{localize "DAGGERHEART.GENERAL.roll"}} -
- - - - - {{#if hasRolled}} - - - - {{/if}} -
-
- - {{#if roll}} -
-
{{roll.total}} {{localize "DAGGERHEART.GENERAL.withThing" thing=roll.totalLabel}}
-
- - {{roll.dHope.total}} - - - + - - {{roll.dFear.total}} - - - {{#if roll.advantage.type}} - {{#if (eq roll.advantage.type 1)}}+{{else}}-{{/if}} - - {{roll.advantage.value}} - - - {{/if}} - {{#if (gte roll.modifierTotal 0)}}+{{else}}-{{/if}} - {{positive roll.modifierTotal}} -
-
- {{else}} - {{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.makeYourRoll"}} - {{/if}} -
- {{/if}} -
-
- {{/with}} -
\ No newline at end of file diff --git a/templates/dialogs/groupRollDialog/main.hbs b/templates/dialogs/groupRollDialog/main.hbs new file mode 100644 index 00000000..6807a7e4 --- /dev/null +++ b/templates/dialogs/groupRollDialog/main.hbs @@ -0,0 +1,15 @@ +
+

{{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.title"}}

+
{{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.members"}}
+
+ {{#each aidKeys as |key|}} +
+ {{/each}} +
+ +
{{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.leader"}}
+
+
{{localize "DAGGERHEART.GENERAL.result.single"}}
+
+
+
\ No newline at end of file diff --git a/templates/dialogs/groupRollDialog/footer.hbs b/templates/dialogs/groupRollDialog/parts/footer.hbs similarity index 62% rename from templates/dialogs/groupRollDialog/footer.hbs rename to templates/dialogs/groupRollDialog/parts/footer.hbs index e401966b..34b4efa1 100644 --- a/templates/dialogs/groupRollDialog/footer.hbs +++ b/templates/dialogs/groupRollDialog/parts/footer.hbs @@ -1,6 +1,9 @@
- +
\ No newline at end of file diff --git a/templates/dialogs/groupRollDialog/parts/member.hbs b/templates/dialogs/groupRollDialog/parts/member.hbs new file mode 100644 index 00000000..ee857794 --- /dev/null +++ b/templates/dialogs/groupRollDialog/parts/member.hbs @@ -0,0 +1,95 @@ +{{#with (ifThen (eq partId "leader") leader (lookup members partId))}} +
+ +
+ {{name}} + {{#if hasRolled}} +
+
{{rollChoiceLabel}}
+ {{#if modifier}} + + {{numberFormat modifier sign=true}} + + {{/if}} + {{#if isEditable}} +
+ + +
+ {{/if}} +
+ {{else if readyToRoll}} +
+ {{localize "DAGGERHEART.CONFIG.RollTypes.trait.name" }} + +
+ {{/if}} +
+ {{#if roll}} +
+
+
+ {{roll.total}} + {{withLabelShort}} +
+
+ + {{roll.dHope.total}} + + + + {{roll.dFear.total}} + + + {{#if roll.hasAdvantage}} + + + + {{roll.dAdvantage.total}} + + + {{/if}} + {{#if roll.hasDisadvantage}} + - + + {{roll.dDisadvantage.total}} + + + {{/if}} + {{#if (gte roll.modifierTotal 0)}}+{{else}}-{{/if}} + {{positive roll.modifierTotal}} +
+
+ {{#if (and @root.isGM (ne ../partId "leader"))}} +
+ + +
+ {{/if}} +
+ {{else if (and readyToRoll isEditable)}} + + 2d12 + + {{/if}} +
+{{/with}} \ No newline at end of file diff --git a/templates/dialogs/groupRollDialog/parts/result.hbs b/templates/dialogs/groupRollDialog/parts/result.hbs new file mode 100644 index 00000000..d90dfb5c --- /dev/null +++ b/templates/dialogs/groupRollDialog/parts/result.hbs @@ -0,0 +1,30 @@ +{{#if (and hasRolled leader.roll)}} +
+
+ {{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.leaderRoll"}} + + {{leader.roll.total}} + {{localize "DAGGERHEART.GENERAL.withThing" thing=leader.roll.totalLabel}} + +
+
+ {{localize "DAGGERHEART.GENERAL.Modifier.plural"}} +
+ {{#each groupRoll.modifiers as |modifier|}} + + {{numberFormat modifier sign=true}} + + {{/each}} +
+
+
+
+ {{localize "DAGGERHEART.GENERAL.total"}} + {{groupRoll.total}} {{groupRoll.totalLabel}} +
+
+{{else}} +
+ {{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.resultsHint"}} +
+{{/if}} \ No newline at end of file diff --git a/templates/settings/variant-rules.hbs b/templates/settings/variant-rules.hbs index cdaef024..9c9650dd 100644 --- a/templates/settings/variant-rules.hbs +++ b/templates/settings/variant-rules.hbs @@ -32,7 +32,7 @@