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.leader"}}
- {{#unless leader.actor}}
-
-
- {{localize "DAGGERHEART.UI.Chat.groupRoll.selectLeader"}}
-
- {{else}}
-
-
-
-
{{leader.actor.name}}
-
-
- {{localize "DAGGERHEART.GENERAL.Trait.single"}}
-
- {{selectOptions traitList selected=leader.trait labelAttr="label" valueAttr="id" localize=true }}
-
-
- {{!-- Not used yet --}}
- {{!--
- {{localize "DAGGERHEART.GENERAL.difficulty"}}
-
-
--}}
-
-
-
-
- {{/unless}}
-
-
-
- {{localize "DAGGERHEART.UI.Chat.groupRoll.partyTeam"}}
-
-
-
- {{#if (gt this.members.length 0)}}
- {{#each members as |member index|}}
-
-
-
-
{{member.actor.name}}
-
-
- {{localize "DAGGERHEART.GENERAL.Trait.single"}}
-
- {{selectOptions @root.traitList selected=member.trait labelAttr="label" valueAttr="id" localize=true }}
-
-
- {{!-- Not used yet --}}
- {{!--
- {{localize "DAGGERHEART.GENERAL.difficulty"}}
-
-
--}}
-
-
-
-
- {{/each}}
- {{/if}}
- {{#unless allSelected}}
-
- {{localize "DAGGERHEART.UI.Chat.groupRoll.selectMember"}}
-
- {{/unless}}
-
-
-
- {{localize "DAGGERHEART.GENERAL.roll"}}
-
-
\ 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)}}
-
-
-
-
-
-
- {{#if readyToRoll}}
-
-
- {{localize "DAGGERHEART.GENERAL.roll"}}
-
-
-
- {{#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"}}
+
+ {{selectOptions selectedLeaderOptions selected=selectedLeader.memberId blank="" }}
+
+
+
+ {{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"}}
-
-
-
-
-
-
-
-
- {{#if readyToRoll}}
-
-
- {{localize "DAGGERHEART.GENERAL.roll"}}
-
-
-
- {{#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 @@
{{localize "COMMON.Cancel"}}
- {{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.finishGroupRoll"}}
+
+
+ {{localize "DAGGERHEART.APPLICATIONS.GroupRollSelect.finishGroupRoll"}}
+
\ 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}}
+
+ {{else if readyToRoll}}
+
+ {{localize "DAGGERHEART.CONFIG.RollTypes.trait.name" }}
+
+ {{selectOptions ../traitOptions selected=rollChoice localize=true}}
+
+
+ {{/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)}}
+
+
+
+ {{/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 @@