Compare commits

...

11 commits
2.3.1 ... main

Author SHA1 Message Date
Carlos Fernandez
a4428fd5be
Replace prettier with stylistic, improve types, and add no-undef rule (#1975)
Some checks are pending
Project CI / build (24.x) (push) Waiting to run
2026-06-05 15:53:15 -04:00
WBHarry
6312a171e2
[Housekeeping] Styles Index:ification (#1977) 2026-06-05 15:36:07 -04:00
WBHarry
3527fd7959 Raised version
Some checks are pending
Project CI / build (24.x) (push) Waiting to run
2026-06-05 12:31:30 +02:00
Carlos Fernandez
f0a7539018
Update README.md (#1976) 2026-06-05 12:25:44 +02:00
Carlos Fernandez
5be79f4ab8
Fix several issues with inline damage (#1973)
Some checks are pending
Project CI / build (24.x) (push) Waiting to run
2026-06-05 11:33:20 +02:00
Carlos Fernandez
2fc5b01f09
Fix rerolling when hope/fear automation is enabled (#1972) 2026-06-05 11:31:01 +02:00
WBHarry
52b81de11f
Fixed so that the saved data for an experience that is in the character data is used over that in the levelup data if available (#1971)
Some checks are pending
Project CI / build (24.x) (push) Waiting to run
2026-06-04 18:30:41 -04:00
Carlos Fernandez
c0c9095847
[Fix] Preload ancestry and community features in description (#1967)
* Preload ancestry and community features in description

* Corrected comments

---------

Co-authored-by: WBHarry <williambjrklund@gmail.com>
2026-06-04 20:08:40 +02:00
Carlos Fernandez
5ac4fc3b9c
[Fix] visual quirk with blur in unfocused countdown (#1970)
Some checks are pending
Project CI / build (24.x) (push) Waiting to run
* Fix visual quirk with blur in unfocused countdown

* Snuck in fixes and refactors
2026-06-04 11:42:17 +02:00
Carlos Fernandez
6747be49b2
Allow removing empty string domains (#1968) 2026-06-04 11:15:41 +02:00
WBHarry
77c5cfcbb7 Fixed so that actions on homebrew downtime/items don't crash due to note having metadata
Some checks are pending
Project CI / build (24.x) (push) Waiting to run
2026-06-03 21:46:23 +02:00
124 changed files with 1128 additions and 834 deletions

View file

@ -1,5 +1,6 @@
[*] [*]
indent_size = 4 indent_size = 4
indent_style = spaces indent_style = spaces
end_of_line = lf
[*.yml] [*.yml]
indent_size = 2 indent_size = 2

View file

@ -1,13 +0,0 @@
{
"trailingComma": "none",
"tabWidth": 4,
"useTabs": false,
"semi": true,
"singleQuote": true,
"quoteProps": "consistent",
"bracketSpacing": true,
"arrowParens": "avoid",
"printWidth": 120,
"endOfLine": "lf",
"bracketSameLine": true
}

View file

@ -66,6 +66,10 @@ You can find the documentation here: https://github.com/Foundryborne/daggerheart
Looking to contribute to the project? Look no further, check out our [contributing guide](CONTRIBUTING.md), and keep the [Code of Conduct](coc.md) in mind when working on things. Looking to contribute to the project? Look no further, check out our [contributing guide](CONTRIBUTING.md), and keep the [Code of Conduct](coc.md) in mind when working on things.
## AI Policy
The Foundryborne Daggerheart system does not make use of AI (generative or otherwise) for any area of its implementation. We expect all contributors to follow this same policy when contributing with a pull request; contributions made using AI will be rejected outright.
## Disclaimer: ## Disclaimer:
**Daggerheart System** **Daggerheart System**

24
daggerheart.d.ts vendored
View file

@ -1,8 +1,11 @@
import '@client/global.mjs'; import '@client/global.mjs';
import '@common/global.mjs';
import '@common/primitives/global.mjs';
import Canvas from '@client/canvas/board.mjs'; import Canvas from '@client/canvas/board.mjs';
// Foundry's use of `Object.assign(globalThis) means many globally available objects are not read as such // Foundry's use of `Object.assign(globalThis) means many globally available objects are not read as such
// This declare global hopefully fixes that // This declare global hopefully fixes that
// Note: eslint is not aware of these, whatever is added here should go in the eslint's globals list
declare global { declare global {
/** /**
* A simple event framework used throughout Foundry Virtual Tabletop. * A simple event framework used throughout Foundry Virtual Tabletop.
@ -12,9 +15,28 @@ declare global {
class Hooks extends foundry.helpers.Hooks {} class Hooks extends foundry.helpers.Hooks {}
const fromUuid = foundry.utils.fromUuid; const fromUuid = foundry.utils.fromUuid;
const fromUuidSync = foundry.utils.fromUuidSync; const fromUuidSync = foundry.utils.fromUuidSync;
/**
* A representation of a color in hexadecimal format.
* This class provides methods for transformations and manipulations of colors.
*/
class Color extends foundry.utils.Color {}
/** /**
* The singleton game canvas * The singleton game canvas
*/ */
const canvas: Canvas; const canvas: Canvas;
const ActiveEffect: foundry.documents.ActiveEffect;
const Actor: foundry.documents.Actor;
const BaseScene: foundry.documents.BaseScene;
const ChatMessage: foundry.documents.ChatMessage;
const Combat: foundry.documents.Combat;
const Combatant: foundry.documents.Combatant;
const Item: foundry.documents.Item;
const Macro: foundry.documents.Macro;
const Scene: foundry.documents.Scene;
const TokenDocument: foundry.documents.TokenDocument;
const Collection: foundry.utils.Collection;
const FormDataExtended: foundry.applications.ux.FormDataExtended;
const TextEditor: foundry.applications.ux.TextEditor;
} }

View file

@ -453,8 +453,8 @@ Hooks.on('renderDialogV2', (_dialog, html) => {
const cls = html.classList.contains('item-create') const cls = html.classList.contains('item-create')
? documents.DHItem.implementation ? documents.DHItem.implementation
: html.classList.contains('actor-create') : html.classList.contains('actor-create')
? documents.DhpActor.implementation ? documents.DhpActor.implementation
: null; : null;
if (!cls) return; if (!cls) return;
const form = html.querySelector('form'); const form = html.querySelector('form');

View file

@ -1,14 +1,101 @@
import globals from 'globals'; import globals from 'globals';
import { defineConfig } from 'eslint/config'; import { defineConfig, globalIgnores } from 'eslint/config';
import prettier from 'eslint-plugin-prettier'; import tseslint from 'typescript-eslint';
import js from '@eslint/js';
import stylistic from '@stylistic/eslint-plugin';
/** @type {Partial<RulesConfig>} */
export const stylisticRules = {
'@stylistic/indent': [
'error',
4,
{
SwitchCase: 1
}
],
'@stylistic/max-len': ['error', {
code: 120,
ignoreComments: true,
ignoreStrings: true,
ignoreTemplateLiterals: true,
ignoreRegExpLiterals: true
}],
'@stylistic/quotes': ['error', 'single', { allowTemplateLiterals: 'always' }],
'@stylistic/arrow-parens': ['error', 'as-needed'],
'@stylistic/quote-props': ['error', 'as-needed'],
'@stylistic/array-bracket-newline': ['error', 'consistent'],
'@stylistic/key-spacing': 'error',
'@stylistic/comma-dangle': ['error', 'never'],
'@stylistic/space-in-parens': ['error', 'never'],
'@stylistic/space-infix-ops': 2,
'@stylistic/keyword-spacing': 2,
'@stylistic/semi-spacing': 2,
'@stylistic/no-multi-spaces': 2,
'@stylistic/no-extra-semi': 2,
'@stylistic/no-whitespace-before-property': 2,
'@stylistic/space-unary-ops': 2
};
export default defineConfig([ export default defineConfig([
{ files: ['**/*.{js,mjs,cjs}'], languageOptions: { globals: globals.browser } }, globalIgnores(['foundry/**/*', 'build/**/*']),
{ plugins: { prettier } }, {
files: ['gulpfile.js', 'postcss.config.js'],
languageOptions: { globals: globals.node }
},
{ {
files: ['**/*.{js,mjs,cjs}'], files: ['**/*.{js,mjs,cjs}'],
plugins: {
'@stylistic': stylistic
},
languageOptions: {
globals: {
...globals.browser,
CONFIG: 'readonly',
CONST: 'readonly',
// Global classes
Color: 'readonly',
Handlebars: 'readonly',
Hooks: 'readonly',
PIXI: 'readonly',
ProseMirror: 'readonly',
Roll: 'readonly',
// global namespaces
canvas: 'readonly',
foundry: 'readonly',
game: 'readonly',
ui: 'readonly',
// global functions
fromUuid: 'readonly',
fromUuidSync: 'readonly',
getDocumentClass: 'readonly',
_del: 'readonly',
_replace: 'readonly',
_loc: 'readonly',
// Documents
ActiveEffect: 'readonly',
Actor: 'readonly',
BaseScene: 'readonly',
ChatMessage: 'readonly',
Combat: 'readonly',
Combatant: 'readonly',
Item: 'readonly',
Macro: 'readonly',
Scene: 'readonly',
TokenDocument: 'readonly',
// Other
Collection: 'readonly',
FormDataExtended: 'readonly',
TextEditor: 'readonly'
}
},
rules: { rules: {
'prettier/prettier': 'error' 'no-undef': 'error',
// 'no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
...stylisticRules
} }
},
{
files: ['**/*.ts'],
extends: [js.configs.recommended, tseslint.configs.recommended]
} }
]); ]);

View file

@ -1,7 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"module": "ES6", "module": "es2022",
"target": "ES6", "target": "es2022",
"paths": { "paths": {
"@client/*": ["./foundry/client/*"], "@client/*": ["./foundry/client/*"],
"@common/*": ["./foundry/common/*"] "@common/*": ["./foundry/common/*"]

View file

@ -154,8 +154,8 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
v.active = this.tabGroups[v.group] v.active = this.tabGroups[v.group]
? this.tabGroups[v.group] === v.id ? this.tabGroups[v.group] === v.id
: this.tabGroups.primary !== 'equipment' : this.tabGroups.primary !== 'equipment'
? v.active ? v.active
: false; : false;
v.cssClass = v.active ? 'active' : ''; v.cssClass = v.active ? 'active' : '';
switch (v.id) { switch (v.id) {
@ -211,9 +211,9 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
context.suggestedTraits = this.setup.class.system context.suggestedTraits = this.setup.class.system
? Object.keys(this.setup.class.system.characterGuide.suggestedTraits).map(traitKey => { ? Object.keys(this.setup.class.system.characterGuide.suggestedTraits).map(traitKey => {
const trait = this.setup.class.system.characterGuide.suggestedTraits[traitKey]; const trait = this.setup.class.system.characterGuide.suggestedTraits[traitKey];
return `${game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${traitKey}.short`)} ${trait > 0 ? `+${trait}` : trait}`; return `${game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${traitKey}.short`)} ${trait > 0 ? `+${trait}` : trait}`;
}) })
: []; : [];
context.traits = { context.traits = {
values: Object.keys(this.setup.traits).map(traitKey => { values: Object.keys(this.setup.traits).map(traitKey => {
@ -450,7 +450,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
if (equipment.includes(type)) if (equipment.includes(type))
presets.filter = { presets.filter = {
'system.tier': { key: 'system.tier', value: 1 }, 'system.tier': { key: 'system.tier', value: 1 },
'type': { key: 'type', value: type } type: { key: 'type', value: type }
}; };
ui.compendiumBrowser.open(presets); ui.compendiumBrowser.open(presets);

View file

@ -196,14 +196,14 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
this.config.costs.indexOf(this.config.costs.find(c => c.extKey === button.dataset.key)) > -1 this.config.costs.indexOf(this.config.costs.find(c => c.extKey === button.dataset.key)) > -1
? this.config.costs.filter(x => x.extKey !== button.dataset.key) ? this.config.costs.filter(x => x.extKey !== button.dataset.key)
: [ : [
...this.config.costs, ...this.config.costs,
{ {
extKey: button.dataset.key, extKey: button.dataset.key,
key: this.config?.data?.parent?.isNPC ? 'fear' : 'hope', key: this.config?.data?.parent?.isNPC ? 'fear' : 'hope',
value: 1, value: 1,
name: this.config.data?.system.experiences?.[button.dataset.key]?.name name: this.config.data?.system.experiences?.[button.dataset.key]?.name
} }
]; ];
this.render(); this.render();
} }
@ -213,8 +213,8 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
this.config.actionType = this.reactionOverride this.config.actionType = this.reactionOverride
? 'reaction' ? 'reaction'
: this.config.actionType === 'reaction' : this.config.actionType === 'reaction'
? 'action' ? 'action'
: this.config.actionType; : this.config.actionType;
this.render(); this.render();
} }
} }

View file

@ -138,13 +138,13 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap
const stressReductionStress = this.availableStressReductions const stressReductionStress = this.availableStressReductions
? stressReductions.reduce((acc, red) => acc + red.cost, 0) ? stressReductions.reduce((acc, red) => acc + red.cost, 0)
: 0; : 0;
const stress = this.actor.system.resources.stress;
context.stress = context.stress =
selectedStressMarks.length > 0 || this.availableStressReductions selectedStressMarks.length > 0 || this.availableStressReductions
? { ? {
value: value: stress.value + selectedStressMarks.length + stressReductionStress,
this.actor.system.resources.stress.value + selectedStressMarks.length + stressReductionStress, max: stress.max
max: this.actor.system.resources.stress.max }
}
: null; : null;
context.maxArmorUsed = maxArmorUsed; context.maxArmorUsed = maxArmorUsed;

View file

@ -259,10 +259,10 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
const resetValue = increasing const resetValue = increasing
? 0 ? 0
: feature.system.resource.max : feature.system.resource.max
? new Roll( ? new Roll(
Roll.replaceFormulaData(feature.system.resource.max, this.actor.getRollData()) Roll.replaceFormulaData(feature.system.resource.max, this.actor.getRollData())
).evaluateSync().total ).evaluateSync().total
: 0; : 0;
await feature.update({ 'system.resource.value': resetValue }); await feature.update({ 'system.resource.value': resetValue });
} }

View file

@ -167,8 +167,8 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
partContext.groupRoll = { partContext.groupRoll = {
totalLabel: leader?.rollData totalLabel: leader?.rollData
? game.i18n.format('DAGGERHEART.GENERAL.withThing', { ? game.i18n.format('DAGGERHEART.GENERAL.withThing', {
thing: leader.roll.totalLabel thing: leader.roll.totalLabel
}) })
: null, : null,
totalDualityClass: leader?.roll?.isCritical ? 'critical' : leader?.roll?.withHope ? 'hope' : 'fear', totalDualityClass: leader?.roll?.isCritical ? 'critical' : leader?.roll?.withHope ? 'hope' : 'fear',
total: leaderTotal + modifierTotal, total: leaderTotal + modifierTotal,

View file

@ -653,8 +653,8 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
const baseSecondaryRoll = selectedRoll const baseSecondaryRoll = selectedRoll
? memberValues.find(x => !x.selected) ? memberValues.find(x => !x.selected)
: memberValues.length > 1 : memberValues.length > 1
? memberValues[1] ? memberValues[1]
: null; : null;
if (!baseMainRoll?.rollData || !baseSecondaryRoll) return null; if (!baseMainRoll?.rollData || !baseSecondaryRoll) return null;

View file

@ -50,11 +50,11 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD {
).showGenericStatusEffects; ).showGenericStatusEffects;
context.genericStatusEffects = useGeneric context.genericStatusEffects = useGeneric
? Object.keys(context.statusEffects).reduce((acc, key) => { ? Object.keys(context.statusEffects).reduce((acc, key) => {
const effect = context.statusEffects[key]; const effect = context.statusEffects[key];
if (!effect.systemEffect) acc[key] = effect; if (!effect.systemEffect) acc[key] = effect;
return acc; return acc;
}, {}) }, {})
: null; : null;
context.hasCompanion = this.actor.system.companion; context.hasCompanion = this.actor.system.companion;
@ -68,11 +68,11 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD {
const warning = const warning =
tokensWithoutActors.length === 1 tokensWithoutActors.length === 1
? game.i18n.format('DAGGERHEART.UI.Notifications.tokenActorMissing', { ? game.i18n.format('DAGGERHEART.UI.Notifications.tokenActorMissing', {
name: tokensWithoutActors[0].name name: tokensWithoutActors[0].name
}) })
: game.i18n.format('DAGGERHEART.UI.Notifications.tokenActorsMissing', { : game.i18n.format('DAGGERHEART.UI.Notifications.tokenActorsMissing', {
names: tokensWithoutActors.map(x => x.name).join(', ') names: tokensWithoutActors.map(x => x.name).join(', ')
}); });
const tokens = canvas.tokens.controlled const tokens = canvas.tokens.controlled
.filter(t => t.actor && !DHTokenHUD.#nonCombatTypes.includes(t.actor.type)) .filter(t => t.actor && !DHTokenHUD.#nonCombatTypes.includes(t.actor.type))
@ -174,8 +174,8 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD {
nonZeroIndex === sideMiddle nonZeroIndex === sideMiddle
? 0 ? 0
: nonZeroIndex < sideMiddle : nonZeroIndex < sideMiddle
? -nonZeroIndex ? -nonZeroIndex
: nonZeroIndex - sideMiddle; : nonZeroIndex - sideMiddle;
return { x: actorX - sizeX * distance, y: actorY - sizeY * distanceCoefficient }; return { x: actorX - sizeX * distance, y: actorY - sizeY * distanceCoefficient };
} else if (index < side + inbetween) { } else if (index < side + inbetween) {
const inbetweenIndex = nonZeroIndex - side; const inbetweenIndex = nonZeroIndex - side;
@ -183,8 +183,8 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD {
inbetweenIndex === inbetweenMiddle inbetweenIndex === inbetweenMiddle
? 0 ? 0
: inbetweenIndex < inbetweenMiddle : inbetweenIndex < inbetweenMiddle
? -inbetweenIndex ? -inbetweenIndex
: inbetweenIndex - inbetweenMiddle; : inbetweenIndex - inbetweenMiddle;
return { x: actorX + sizeX * distanceCoefficient, y: actorY + sizeY * distance }; return { x: actorX + sizeX * distanceCoefficient, y: actorY + sizeY * distance };
} else if (index < 2 * side + inbetween) { } else if (index < 2 * side + inbetween) {
const sideIndex = nonZeroIndex - side - inbetween; const sideIndex = nonZeroIndex - side - inbetween;
@ -192,8 +192,8 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD {
sideIndex === sideMiddle sideIndex === sideMiddle
? 0 ? 0
: sideIndex < sideMiddle : sideIndex < sideMiddle
? sideIndex ? sideIndex
: -(sideIndex - sideMiddle); : -(sideIndex - sideMiddle);
return { x: actorX + sizeX * distance, y: actorY + sizeY * distanceCoefficient }; return { x: actorX + sizeX * distance, y: actorY + sizeY * distanceCoefficient };
} else { } else {
const inbetweenIndex = nonZeroIndex - 2 * side - inbetween; const inbetweenIndex = nonZeroIndex - 2 * side - inbetween;
@ -201,8 +201,8 @@ export default class DHTokenHUD extends foundry.applications.hud.TokenHUD {
inbetweenIndex === inbetweenMiddle inbetweenIndex === inbetweenMiddle
? 0 ? 0
: inbetweenIndex < inbetweenMiddle : inbetweenIndex < inbetweenMiddle
? inbetweenIndex ? inbetweenIndex
: -(inbetweenIndex - inbetweenMiddle); : -(inbetweenIndex - inbetweenMiddle);
return { x: actorX - sizeX * distanceCoefficient, y: actorY + sizeY * distance }; return { x: actorX - sizeX * distanceCoefficient, y: actorY + sizeY * distance };
} }
}) })

View file

@ -210,9 +210,9 @@ export default class DhCharacterLevelUp extends LevelUpBase {
achievementExperiences = level.achievements.experiences achievementExperiences = level.achievements.experiences
? Object.values(level.achievements.experiences).reduce((acc, experience) => { ? Object.values(level.achievements.experiences).reduce((acc, experience) => {
if (experience.name) acc.push(experience); if (experience.name) acc.push(experience);
return acc; return acc;
}, []) }, [])
: []; : [];
} }
@ -315,15 +315,15 @@ export default class DhCharacterLevelUp extends LevelUpBase {
: null; : null;
advancement[choiceKey] = multiclassItem advancement[choiceKey] = multiclassItem
? { ? {
...multiclassItem.toObject(), ...multiclassItem.toObject(),
domain: checkbox.secondaryData.domain domain: checkbox.secondaryData.domain
? game.i18n.localize( ? game.i18n.localize(
CONFIG.DH.DOMAIN.allDomains()[checkbox.secondaryData.domain] CONFIG.DH.DOMAIN.allDomains()[checkbox.secondaryData.domain]
.label .label
) )
: null, : null,
subclass: subclass ? subclass.name : null subclass: subclass ? subclass.name : null
} }
: {}; : {};
break; break;
} }

View file

@ -77,9 +77,9 @@ export default class DhCompanionLevelUp extends BaseLevelUp {
achievementExperiences = level.achievements.experiences achievementExperiences = level.achievements.experiences
? Object.values(level.achievements.experiences).reduce((acc, experience) => { ? Object.values(level.achievements.experiences).reduce((acc, experience) => {
if (experience.name) acc.push(experience); if (experience.name) acc.push(experience);
return acc; return acc;
}, []) }, [])
: []; : [];
} }
context.achievements = { context.achievements = {
@ -155,15 +155,15 @@ export default class DhCompanionLevelUp extends BaseLevelUp {
vicious: { vicious: {
damage: advancement.vicious?.damage damage: advancement.vicious?.damage
? { ? {
old: actorDamageDice, old: actorDamageDice,
new: advancement.vicious.damage new: advancement.vicious.damage
} }
: null, : null,
range: advancement.vicious?.range range: advancement.vicious?.range
? { ? {
old: game.i18n.localize(`DAGGERHEART.CONFIG.Range.${actorRange}.name`), old: game.i18n.localize(`DAGGERHEART.CONFIG.Range.${actorRange}.name`),
new: game.i18n.localize(advancement.vicious.range.label) new: game.i18n.localize(advancement.vicious.range.label)
} }
: null : null
}, },
simple: advancement.simple ?? {} simple: advancement.simple ?? {}

View file

@ -135,192 +135,6 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
context.tabs.advancements.progress = { selected: selections, max: currentLevel.maxSelections }; context.tabs.advancements.progress = { selected: selections, max: currentLevel.maxSelections };
context.showTabs = this.tabGroups.primary !== 'summary'; context.showTabs = this.tabGroups.primary !== 'summary';
break; break;
const actorArmor = this.actor.system.armor;
const levelKeys = Object.keys(this.levelup.levels);
let achivementProficiency = 0;
const achievementCards = [];
let achievementExperiences = [];
for (var levelKey of levelKeys) {
const level = this.levelup.levels[levelKey];
if (Number(levelKey) < this.levelup.startLevel) continue;
achivementProficiency += level.achievements.proficiency ?? 0;
const cards = level.achievements.domainCards ? Object.values(level.achievements.domainCards) : null;
if (cards) {
for (var card of cards) {
const itemCard = await foundry.utils.fromUuid(card.uuid);
achievementCards.push(itemCard);
}
}
achievementExperiences = level.achievements.experiences
? Object.values(level.achievements.experiences).reduce((acc, experience) => {
if (experience.name) acc.push(experience);
return acc;
}, [])
: [];
}
context.achievements = {
proficiency: {
old: this.actor.system.proficiency,
new: this.actor.system.proficiency + achivementProficiency,
shown: achivementProficiency > 0
},
damageThresholds: {
major: {
old: this.actor.system.damageThresholds.major,
new: this.actor.system.damageThresholds.major + changedActorLevel - currentActorLevel
},
severe: {
old: this.actor.system.damageThresholds.severe,
new:
this.actor.system.damageThresholds.severe +
(actorArmor
? changedActorLevel - currentActorLevel
: (changedActorLevel - currentActorLevel) * 2)
},
unarmored: !actorArmor
},
domainCards: {
values: achievementCards,
shown: achievementCards.length > 0
},
experiences: {
values: achievementExperiences
}
};
const advancement = {};
for (var levelKey of levelKeys) {
const level = this.levelup.levels[levelKey];
if (Number(levelKey) < this.levelup.startLevel) continue;
for (var choiceKey of Object.keys(level.choices)) {
const choice = level.choices[choiceKey];
for (var checkbox of Object.values(choice)) {
switch (choiceKey) {
case 'proficiency':
case 'hitPoint':
case 'stress':
case 'evasion':
advancement[choiceKey] = advancement[choiceKey]
? advancement[choiceKey] + Number(checkbox.value)
: Number(checkbox.value);
break;
case 'trait':
if (!advancement[choiceKey]) advancement[choiceKey] = {};
for (var traitKey of checkbox.data) {
if (!advancement[choiceKey][traitKey]) advancement[choiceKey][traitKey] = 0;
advancement[choiceKey][traitKey] += 1;
}
break;
case 'domainCard':
if (!advancement[choiceKey]) advancement[choiceKey] = [];
if (checkbox.data.length === 1) {
const choiceItem = await foundry.utils.fromUuid(checkbox.data[0]);
advancement[choiceKey].push(choiceItem.toObject());
}
break;
case 'experience':
if (!advancement[choiceKey]) advancement[choiceKey] = [];
const data = checkbox.data.map(data => {
const experience = Object.keys(this.actor.system.experiences).find(
x => x === data
);
return this.actor.system.experiences[experience]?.description ?? '';
});
advancement[choiceKey].push({ data: data, value: checkbox.value });
break;
case 'subclass':
if (checkbox.data[0]) {
const subclassItem = await foundry.utils.fromUuid(checkbox.data[0]);
if (!advancement[choiceKey]) advancement[choiceKey] = [];
advancement[choiceKey].push({
...subclassItem.toObject(),
featureLabel: game.i18n.localize(
subclassFeatureLabels[Number(checkbox.secondaryData.featureState)]
)
});
}
break;
case 'multiclass':
const multiclassItem = await foundry.utils.fromUuid(checkbox.data[0]);
const subclass = multiclassItem
? await foundry.utils.fromUuid(checkbox.secondaryData.subclass)
: null;
advancement[choiceKey] = multiclassItem
? {
...multiclassItem.toObject(),
domain: checkbox.secondaryData.domain
? game.i18n.localize(
CONFIG.DH.DOMAIN.allDomains()[checkbox.secondaryData.domain]
.label
)
: null,
subclass: subclass ? subclass.name : null
}
: {};
break;
}
}
}
}
context.advancements = {
statistics: {
proficiency: {
old: context.achievements.proficiency.new,
new: context.achievements.proficiency.new + (advancement.proficiency ?? 0)
},
hitPoints: {
old: this.actor.system.resources.hitPoints.max,
new: this.actor.system.resources.hitPoints.max + (advancement.hitPoint ?? 0)
},
stress: {
old: this.actor.system.resources.stress.max,
new: this.actor.system.resources.stress.max + (advancement.stress ?? 0)
},
evasion: {
old: this.actor.system.evasion,
new: this.actor.system.evasion + (advancement.evasion ?? 0)
}
},
traits: Object.keys(this.actor.system.traits).reduce((acc, traitKey) => {
if (advancement.trait?.[traitKey]) {
if (!acc) acc = {};
acc[traitKey] = {
label: game.i18n.localize(abilities[traitKey].label),
old: this.actor.system.traits[traitKey].value,
new: this.actor.system.traits[traitKey].value + advancement.trait[traitKey]
};
}
return acc;
}, null),
domainCards: advancement.domainCard ?? [],
experiences:
advancement.experience?.flatMap(x => x.data.map(data => ({ name: data, modifier: x.value }))) ??
[],
multiclass: advancement.multiclass,
subclass: advancement.subclass
};
context.advancements.statistics.proficiency.shown =
context.advancements.statistics.proficiency.new > context.advancements.statistics.proficiency.old;
context.advancements.statistics.hitPoints.shown =
context.advancements.statistics.hitPoints.new > context.advancements.statistics.hitPoints.old;
context.advancements.statistics.stress.shown =
context.advancements.statistics.stress.new > context.advancements.statistics.stress.old;
context.advancements.statistics.evasion.shown =
context.advancements.statistics.evasion.new > context.advancements.statistics.evasion.old;
context.advancements.statistics.shown =
context.advancements.statistics.proficiency.shown ||
context.advancements.statistics.hitPoints.shown ||
context.advancements.statistics.stress.shown ||
context.advancements.statistics.evasion.shown;
break;
} }
return context; return context;
@ -358,14 +172,14 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
const experienceIncreaseTagify = htmlElement.querySelector('.levelup-experience-increases'); const experienceIncreaseTagify = htmlElement.querySelector('.levelup-experience-increases');
if (experienceIncreaseTagify) { if (experienceIncreaseTagify) {
const allExperiences = { const allExperiences = {
...this.actor.system.experiences,
...Object.values(this.levelup.levels).reduce((acc, level) => { ...Object.values(this.levelup.levels).reduce((acc, level) => {
for (const key of Object.keys(level.achievements.experiences)) { for (const key of Object.keys(level.achievements.experiences)) {
acc[key] = level.achievements.experiences[key]; acc[key] = level.achievements.experiences[key];
} }
return acc; return acc;
}, {}) }, {}),
...this.actor.system.experiences
}; };
tagifyElement( tagifyElement(
experienceIncreaseTagify, experienceIncreaseTagify,
@ -384,37 +198,35 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
this._dragDrop.forEach(d => d.bind(htmlElement)); this._dragDrop.forEach(d => d.bind(htmlElement));
} }
tagifyUpdate = tagifyUpdate = type => async (_, { option, removed }) => {
type => const updatePath = Object.keys(this.levelup.levels[this.levelup.currentLevel].choices).reduce(
async (_, { option, removed }) => { (acc, choiceKey) => {
const updatePath = Object.keys(this.levelup.levels[this.levelup.currentLevel].choices).reduce( const choice = this.levelup.levels[this.levelup.currentLevel].choices[choiceKey];
(acc, choiceKey) => { Object.keys(choice).forEach(checkboxNr => {
const choice = this.levelup.levels[this.levelup.currentLevel].choices[choiceKey]; const checkbox = choice[checkboxNr];
Object.keys(choice).forEach(checkboxNr => { if (
const checkbox = choice[checkboxNr]; choiceKey === type &&
if ( (removed ? checkbox.data.includes(option) : checkbox.data.length < checkbox.amount)
choiceKey === type && ) {
(removed ? checkbox.data.includes(option) : checkbox.data.length < checkbox.amount) acc = `levels.${this.levelup.currentLevel}.choices.${choiceKey}.${checkboxNr}.data`;
) { }
acc = `levels.${this.levelup.currentLevel}.choices.${choiceKey}.${checkboxNr}.data`; });
}
});
return acc; return acc;
}, },
null null
); );
if (!updatePath) { if (!updatePath) {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.noSelectionsLeft')); ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.noSelectionsLeft'));
return; return;
} }
const currentData = foundry.utils.getProperty(this.levelup, updatePath); const currentData = foundry.utils.getProperty(this.levelup, updatePath);
const updatedData = removed ? currentData.filter(x => x !== option) : [...currentData, option]; const updatedData = removed ? currentData.filter(x => x !== option) : [...currentData, option];
await this.levelup.updateSource({ [updatePath]: updatedData }); await this.levelup.updateSource({ [updatePath]: updatedData });
this.render(); this.render();
}; };
static async updateForm(event, _, formData) { static async updateForm(event, _, formData) {
const { levelup } = foundry.utils.expandObject(formData.object); const { levelup } = foundry.utils.expandObject(formData.object);
@ -593,10 +405,10 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
const domainCards = this.levelup.levels[this.levelup.currentLevel].achievements.domainCards; const domainCards = this.levelup.levels[this.levelup.currentLevel].achievements.domainCards;
const illegalDomainCards = option.secondaryData.domain const illegalDomainCards = option.secondaryData.domain
? Object.keys(domainCards) ? Object.keys(domainCards)
.map(key => ({ ...domainCards[key], key })) .map(key => ({ ...domainCards[key], key }))
.filter( .filter(
x => x.uuid && foundry.utils.fromUuidSync(x.uuid).system.domain === option.secondaryData.domain x => x.uuid && foundry.utils.fromUuidSync(x.uuid).system.domain === option.secondaryData.domain
) )
: []; : [];
illegalDomainCards.forEach(card => { illegalDomainCards.forEach(card => {
update[`levels.${this.levelup.currentLevel}.achievements.domainCards.${card.key}.uuid`] = null; update[`levels.${this.levelup.currentLevel}.achievements.domainCards.${card.key}.uuid`] = null;

View file

@ -111,7 +111,7 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
switch (partId) { switch (partId) {
case 'domains': case 'domains':
const selectedDomain = this.selected.domain ? this.settings.domains[this.selected.domain] : null; const selectedDomain = this.settings.domains[this.selected.domain] ?? null;
const enrichedDescription = selectedDomain const enrichedDescription = selectedDomain
? await foundry.applications.ux.TextEditor.implementation.enrichHTML(selectedDomain.description) ? await foundry.applications.ux.TextEditor.implementation.enrichHTML(selectedDomain.description)
: null; : null;
@ -251,8 +251,8 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
const configTitle = isDowntime const configTitle = isDowntime
? game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.downtimeMove') ? game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.downtimeMove')
: type === 'armorFeatures' : type === 'armorFeatures'
? game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.armorFeature') ? game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.armorFeature')
: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.weaponFeature'); : game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.weaponFeature');
const editedBase = await game.system.api.applications.sheetConfigs.SettingFeatureConfig.configure( const editedBase = await game.system.api.applications.sheetConfigs.SettingFeatureConfig.configure(
configTitle, configTitle,

View file

@ -204,7 +204,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
}; };
} }
if (this.action.parent.metadata.isInventoryItem) { if (this.action.parent.metadata?.isInventoryItem) {
options.quantity = { options.quantity = {
label: 'DAGGERHEART.GENERAL.itemQuantity', label: 'DAGGERHEART.GENERAL.itemQuantity',
group: 'Global' group: 'Global'

View file

@ -168,8 +168,8 @@ export default class SettingFeatureConfig extends HandlebarsApplicationMixin(App
updatedEffects = deleteEffect updatedEffects = deleteEffect
? currentEffects.filter(x => x.id !== effectData.id) ? currentEffects.filter(x => x.id !== effectData.id)
: existingEffectIndex === -1 : existingEffectIndex === -1
? [...currentEffects, effectData] ? [...currentEffects, effectData]
: currentEffects.with(existingEffectIndex, effectData); : currentEffects.with(existingEffectIndex, effectData);
await this.updateMove({ await this.updateMove({
[`${this.movePath}.effects`]: updatedEffects [`${this.movePath}.effects`]: updatedEffects
}); });
@ -235,9 +235,9 @@ export default class SettingFeatureConfig extends HandlebarsApplicationMixin(App
return this.hasEffects return this.hasEffects
? tabs ? tabs
: Object.keys(tabs).reduce((acc, key) => { : Object.keys(tabs).reduce((acc, key) => {
if (key !== 'effects') acc[key] = tabs[key]; if (key !== 'effects') acc[key] = tabs[key];
return acc; return acc;
}, {}); }, {});
} }
/** @override */ /** @override */

View file

@ -785,11 +785,11 @@ export default class CharacterSheet extends DHBaseActorSheet {
filter: filter:
key === 'subclasses' key === 'subclasses'
? { ? {
'system.linkedClass.uuid': { 'system.linkedClass.uuid': {
key: 'system.linkedClass.uuid', key: 'system.linkedClass.uuid',
value: this.document.system.class.value?._stats.compendiumSource value: this.document.system.class.value?._stats.compendiumSource
} }
} }
: undefined, : undefined,
render: { render: {
noFolder: true noFolder: true

View file

@ -162,9 +162,9 @@ export default class Party extends DHBaseActorSheet {
difficulty: actor.system.difficulty, difficulty: actor.system.difficulty,
traits: actor.system.traits traits: actor.system.traits
? traits.map(t => ({ ? traits.map(t => ({
label: game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${t}.short`), label: game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${t}.short`),
value: actor.system.traits[t].value value: actor.system.traits[t].value
})) }))
: null, : null,
weapons weapons
}); });
@ -306,7 +306,7 @@ export default class Party extends DHBaseActorSheet {
static async downtimeMoveQuery({ actorId, downtimeType }) { static async downtimeMoveQuery({ actorId, downtimeType }) {
const actor = await foundry.utils.fromUuid(actorId); const actor = await foundry.utils.fromUuid(actorId);
if (!actor || !actor?.isOwner) reject(); if (!actor || !actor?.isOwner) return;
new game.system.api.applications.dialogs.Downtime(actor, downtimeType === 'shortRest').render({ new game.system.api.applications.dialogs.Downtime(actor, downtimeType === 'shortRest').render({
force: true force: true
}); });

View file

@ -722,10 +722,10 @@ export default function DHApplicationMixin(Base) {
const parent = featureOnCharacter const parent = featureOnCharacter
? this.document.parent ? this.document.parent
: parentIsItem && documentClass === 'Item' : parentIsItem && documentClass === 'Item'
? type === 'action' ? type === 'action'
? this.document.system ? this.document.system
: null : null
: this.document; : this.document;
let systemData = {}; let systemData = {};
if (featureOnCharacter) { if (featureOnCharacter) {

View file

@ -377,7 +377,7 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
action: 'update', action: 'update',
documentName: 'Item', documentName: 'Item',
parent: targetActor, parent: targetActor,
updates: [{ '_id': existing.id, 'system.quantity': existing.system.quantity + quantity }] updates: [{ _id: existing.id, 'system.quantity': existing.system.quantity + quantity }]
}); });
} else { } else {
const itemsToCreate = []; const itemsToCreate = [];
@ -410,7 +410,7 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
action: 'update', action: 'update',
documentName: 'Item', documentName: 'Item',
parent: originActor, parent: originActor,
updates: [{ '_id': item.id, 'system.quantity': item.system.quantity - quantity }] updates: [{ _id: item.id, 'system.quantity': item.system.quantity - quantity }]
}); });
} }

View file

@ -29,16 +29,6 @@ export default function ItemAttachmentSheet(Base) {
} }
}; };
async _preparePartContext(partId, context) {
await super._preparePartContext(partId, context);
if (partId === 'attachments') {
context.attachedItems = await prepareAttachmentContext(this.document);
}
return context;
}
async _onDrop(event) { async _onDrop(event) {
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);

View file

@ -13,8 +13,8 @@ export default class DhActorDirectory extends foundry.applications.sidebar.tabs.
return document.type === 'adversary' return document.type === 'adversary'
? game.i18n.localize(adversaryTypes[document.system.type]?.label ?? 'TYPES.Actor.adversary') ? game.i18n.localize(adversaryTypes[document.system.type]?.label ?? 'TYPES.Actor.adversary')
: document.type === 'environment' : document.type === 'environment'
? game.i18n.localize(environmentTypes[document.system.type]?.label ?? 'TYPES.Actor.environment') ? game.i18n.localize(environmentTypes[document.system.type]?.label ?? 'TYPES.Actor.environment')
: null; : null;
}; };
} }

View file

@ -41,8 +41,8 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
const advantage = rollCommand.advantage const advantage = rollCommand.advantage
? CONFIG.DH.ACTIONS.advantageState.advantage.value ? CONFIG.DH.ACTIONS.advantageState.advantage.value
: rollCommand.disadvantage : rollCommand.disadvantage
? CONFIG.DH.ACTIONS.advantageState.disadvantage.value ? CONFIG.DH.ACTIONS.advantageState.disadvantage.value
: undefined; : undefined;
const difficulty = rollCommand.difficulty; const difficulty = rollCommand.difficulty;
const grantResources = rollCommand.grantResources; const grantResources = rollCommand.grantResources;
@ -50,8 +50,8 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
const title = const title =
(flavor ?? traitValue) (flavor ?? traitValue)
? game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { ? game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', {
ability: game.i18n.localize(SYSTEM.ACTOR.abilities[traitValue].label) ability: game.i18n.localize(CONFIG.DH.ACTOR.abilities[traitValue].label)
}) })
: game.i18n.localize('DAGGERHEART.GENERAL.duality'); : game.i18n.localize('DAGGERHEART.GENERAL.duality');
enrichedDualityRoll({ enrichedDualityRoll({

View file

@ -56,8 +56,8 @@ export default class CountdownEdit extends HandlebarsApplicationMixin(Applicatio
? countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.increasing.id ? countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.increasing.id
? 'DAGGERHEART.UI.Countdowns.increasingLoop' ? 'DAGGERHEART.UI.Countdowns.increasingLoop'
: countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.decreasing.id : countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.decreasing.id
? 'DAGGERHEART.UI.Countdowns.decreasingLoop' ? 'DAGGERHEART.UI.Countdowns.decreasingLoop'
: 'DAGGERHEART.UI.Countdowns.loop' : 'DAGGERHEART.UI.Countdowns.loop'
: null; : null;
const randomizeValid = !new Roll(countdown.progress.startFormula ?? '').isDeterministic; const randomizeValid = !new Roll(countdown.progress.startFormula ?? '').isDeterministic;
acc[key] = { acc[key] = {
@ -148,11 +148,11 @@ export default class CountdownEdit extends HandlebarsApplicationMixin(Applicatio
} }
async gmSetSetting(data) { async gmSetSetting(data) {
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, data), await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, data);
game.socket.emit(`system.${CONFIG.DH.id}`, { game.socket.emit(`system.${CONFIG.DH.id}`, {
action: socketEvent.Refresh, action: socketEvent.Refresh,
data: { refreshType: RefreshType.Countdown } data: { refreshType: RefreshType.Countdown }
}); });
Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.Countdown }); Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.Countdown });
} }

View file

@ -31,9 +31,9 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
minimizable: false minimizable: false
}, },
actions: { actions: {
toggleViewMode: DhCountdowns.#toggleViewMode, toggleViewMode: DhCountdowns.#onToggleViewMode,
editCountdowns: DhCountdowns.#editCountdowns, editCountdowns: DhCountdowns.#onEditCountdowns,
loopCountdown: DhCountdowns.#loopCountdown, loopCountdown: DhCountdowns.#onLoopCountdown,
decreaseCountdown: (_, target) => this.editCountdown(false, target), decreaseCountdown: (_, target) => this.editCountdown(false, target),
increaseCountdown: (_, target) => this.editCountdown(true, target) increaseCountdown: (_, target) => this.editCountdown(true, target)
}, },
@ -101,8 +101,8 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
? countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.increasing.id ? countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.increasing.id
? 'DAGGERHEART.UI.Countdowns.increasingLoop' ? 'DAGGERHEART.UI.Countdowns.increasingLoop'
: countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.decreasing.id : countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.decreasing.id
? 'DAGGERHEART.UI.Countdowns.decreasingLoop' ? 'DAGGERHEART.UI.Countdowns.decreasingLoop'
: 'DAGGERHEART.UI.Countdowns.loop' : 'DAGGERHEART.UI.Countdowns.loop'
: null; : null;
const loopDisabled = const loopDisabled =
!countdownEditable || !countdownEditable ||
@ -147,7 +147,7 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
return true; return true;
} }
static async #toggleViewMode() { static async #onToggleViewMode() {
const currentMode = game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownMode); const currentMode = game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.userFlags.countdownMode);
const appMode = CONFIG.DH.GENERAL.countdownAppMode; const appMode = CONFIG.DH.GENERAL.countdownAppMode;
const newMode = currentMode === appMode.textIcon ? appMode.iconOnly : appMode.textIcon; const newMode = currentMode === appMode.textIcon ? appMode.iconOnly : appMode.textIcon;
@ -158,15 +158,16 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
this.render(); this.render();
} }
static async #editCountdowns() { static async #onEditCountdowns() {
new game.system.api.applications.ui.CountdownEdit().render(true); new game.system.api.applications.ui.CountdownEdit().render(true);
} }
static async #loopCountdown(_, target) { static async #onLoopCountdown(_, target) {
if (!DhCountdowns.canPerformEdit()) return; if (!DhCountdowns.canPerformEdit()) return;
const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns); const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns);
const countdown = settings.countdowns[target.id]; const countdownId = target.closest('[data-countdown]').dataset.countdown;
const countdown = settings.countdowns[countdownId];
let progressMax = countdown.progress.start; let progressMax = countdown.progress.start;
let message = null; let message = null;
@ -180,12 +181,12 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.increasing.id countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.increasing.id
? Number(progressMax) + 1 ? Number(progressMax) + 1
: countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.decreasing.id : countdown.progress.looping === CONFIG.DH.GENERAL.countdownLoopingTypes.decreasing.id
? Math.max(Number(progressMax) - 1, 0) ? Math.max(Number(progressMax) - 1, 0)
: progressMax; : progressMax;
await waitForDiceSoNice(message); await waitForDiceSoNice(message);
await settings.updateSource({ await settings.updateSource({
[`countdowns.${target.id}.progress`]: { [`countdowns.${countdownId}.progress`]: {
current: newMax, current: newMax,
start: newMax start: newMax
} }
@ -199,22 +200,23 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
if (!DhCountdowns.canPerformEdit()) return; if (!DhCountdowns.canPerformEdit()) return;
const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns); const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns);
const countdown = settings.countdowns[target.id]; const countdownId = target.closest('[data-countdown]').dataset.countdown;
const countdown = settings.countdowns[countdownId];
const newCurrent = increase const newCurrent = increase
? Math.min(countdown.progress.current + 1, countdown.progress.start) ? Math.min(countdown.progress.current + 1, countdown.progress.start)
: Math.max(countdown.progress.current - 1, 0); : Math.max(countdown.progress.current - 1, 0);
await settings.updateSource({ [`countdowns.${target.id}.progress.current`]: newCurrent }); await settings.updateSource({ [`countdowns.${countdownId}.progress.current`]: newCurrent });
await emitGMUpdate(GMUpdateEvent.UpdateCountdowns, DhCountdowns.gmSetSetting.bind(settings), settings, null, { await emitGMUpdate(GMUpdateEvent.UpdateCountdowns, DhCountdowns.gmSetSetting.bind(settings), settings, null, {
refreshType: RefreshType.Countdown refreshType: RefreshType.Countdown
}); });
} }
static async gmSetSetting(data) { static async gmSetSetting(data) {
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, data), await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, data);
game.socket.emit(`system.${CONFIG.DH.id}`, { game.socket.emit(`system.${CONFIG.DH.id}`, {
action: socketEvent.Refresh, action: socketEvent.Refresh,
data: { refreshType: RefreshType.Countdown } data: { refreshType: RefreshType.Countdown }
}); });
Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.Countdown }); Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.Countdown });
} }

View file

@ -67,10 +67,10 @@ export default class DhEffectsDisplay extends HandlebarsApplicationMixin(Applica
const actor = token const actor = token
? token.actor ? token.actor
: canvas.tokens.controlled.length === 0 : canvas.tokens.controlled.length === 0
? !game.user.isGM ? !game.user.isGM
? game.user.character ? game.user.character
: null : null
: canvas.tokens.controlled[0].actor; : canvas.tokens.controlled[0].actor;
return getIconVisibleActiveEffects(actor?.getActiveEffects() ?? []); return getIconVisibleActiveEffects(actor?.getActiveEffects() ?? []);
}; };

View file

@ -155,15 +155,15 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token {
const targetEdge = this.#getEdgeBoundary(targetBounds, originPoint, targetPoint); const targetEdge = this.#getEdgeBoundary(targetBounds, originPoint, targetPoint);
const adjustedOriginPoint = originEdge const adjustedOriginPoint = originEdge
? canvas.grid.getTopLeftPoint({ ? canvas.grid.getTopLeftPoint({
x: originEdge.x + Math.sign(originPoint.x - originEdge.x), x: originEdge.x + Math.sign(originPoint.x - originEdge.x),
y: originEdge.y + Math.sign(originPoint.y - originEdge.y) y: originEdge.y + Math.sign(originPoint.y - originEdge.y)
}) })
: originPoint; : originPoint;
const adjustDestinationPoint = targetEdge const adjustDestinationPoint = targetEdge
? canvas.grid.getTopLeftPoint({ ? canvas.grid.getTopLeftPoint({
x: targetEdge.x + Math.sign(targetPoint.x - targetEdge.x), x: targetEdge.x + Math.sign(targetPoint.x - targetEdge.x),
y: targetEdge.y + Math.sign(targetPoint.y - targetEdge.y) y: targetEdge.y + Math.sign(targetPoint.y - targetEdge.y)
}) })
: targetPoint; : targetPoint;
const distance = canvas.grid.measurePath([ const distance = canvas.grid.measurePath([
{ ...adjustedOriginPoint, elevation: 0 }, { ...adjustedOriginPoint, elevation: 0 },

View file

@ -127,8 +127,8 @@ export const typeConfig = {
isSecondary isSecondary
? 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon.short' ? 'DAGGERHEART.ITEMS.Weapon.secondaryWeapon.short'
: isSecondary === false : isSecondary === false
? 'DAGGERHEART.ITEMS.Weapon.primaryWeapon.short' ? 'DAGGERHEART.ITEMS.Weapon.primaryWeapon.short'
: '-' : '-'
}, },
{ {
key: 'system.tier', key: 'system.tier',

View file

@ -79,8 +79,8 @@ export default class DHAttackAction extends DHDamageAction {
const str = damageString const str = damageString
? damageString ? damageString
: game.i18n.format('DAGGERHEART.GENERAL.missingX', { : game.i18n.format('DAGGERHEART.GENERAL.missingX', {
x: game.i18n.localize('DAGGERHEART.GENERAL.damage') x: game.i18n.localize('DAGGERHEART.GENERAL.damage')
}); });
const icons = Array.from(type) const icons = Array.from(type)
.map(t => CONFIG.DH.GENERAL.damageTypes[t]?.icon) .map(t => CONFIG.DH.GENERAL.damageTypes[t]?.icon)

View file

@ -144,8 +144,8 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
return this.item instanceof DhpActor return this.item instanceof DhpActor
? this.item ? this.item
: this.item?.parent instanceof DhpActor : this.item?.parent instanceof DhpActor
? this.item.parent ? this.item.parent
: null; : null;
} }
/** /**
@ -223,7 +223,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
* @returns {object} * @returns {object}
*/ */
async use(event, configOptions = {}) { async use(event, configOptions = {}) {
if (!this.actor) throw new Error("An Action can't be used outside of an Actor context."); if (!this.actor) throw new Error('An Action can\'t be used outside of an Actor context.');
let config = this.prepareConfig(event, configOptions); let config = this.prepareConfig(event, configOptions);
if (!config) return; if (!config) return;
@ -300,17 +300,17 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
const groupAttackTokens = this.damage.groupAttack const groupAttackTokens = this.damage.groupAttack
? game.system.api.fields.ActionFields.DamageField.getGroupAttackTokens( ? game.system.api.fields.ActionFields.DamageField.getGroupAttackTokens(
this.actor.id, this.actor.id,
this.damage.groupAttack this.damage.groupAttack
) )
: null; : null;
config.damageOptions = { config.damageOptions = {
groupAttack: this.damage.groupAttack groupAttack: this.damage.groupAttack
? { ? {
numAttackers: Math.max(groupAttackTokens.length, 1), numAttackers: Math.max(groupAttackTokens.length, 1),
range: this.damage.groupAttack range: this.damage.groupAttack
} }
: null : null
}; };
} }

View file

@ -90,13 +90,13 @@ export default class BeastformEffect extends BaseEffect {
...baseUpdate, ...baseUpdate,
x, x,
y, y,
'texture': { texture: {
enabled: this.characterTokenData.usesDynamicToken, enabled: this.characterTokenData.usesDynamicToken,
src: token.flags.daggerheart?.beastformTokenImg ?? this.characterTokenData.tokenImg, src: token.flags.daggerheart?.beastformTokenImg ?? this.characterTokenData.tokenImg,
scaleX: this.characterTokenData.tokenSize.scale, scaleX: this.characterTokenData.tokenSize.scale,
scaleY: this.characterTokenData.tokenSize.scale scaleY: this.characterTokenData.tokenSize.scale
}, },
'ring': { ring: {
subject: { subject: {
texture: texture:
token.flags.daggerheart?.beastformSubjectTexture ?? this.characterTokenData.tokenRingImg token.flags.daggerheart?.beastformSubjectTexture ?? this.characterTokenData.tokenRingImg

View file

@ -166,10 +166,10 @@ export default class ArmorChange extends foundry.abstract.DataModel {
value: value:
change.type === 'armor' change.type === 'armor'
? { ? {
...change.value, ...change.value,
current: Math.min(change.value.current, newMax), current: Math.min(change.value.current, newMax),
max: newMax max: newMax
} }
: change.value : change.value
})) }))
]; ];

View file

@ -315,8 +315,8 @@ export default class DhCharacter extends DhCreature {
return currentLevel === 1 return currentLevel === 1
? 1 ? 1
: Object.values(game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers).find( : Object.values(game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers).find(
tier => currentLevel >= tier.levels.start && currentLevel <= tier.levels.end tier => currentLevel >= tier.levels.start && currentLevel <= tier.levels.end
).tier; ).tier;
} }
get ancestry() { get ancestry() {
@ -520,20 +520,20 @@ export default class DhCharacter extends DhCreature {
if (armorSource.type === 'armor') { if (armorSource.type === 'armor') {
armorUpdates[armorSource.parent.id].updates.push({ armorUpdates[armorSource.parent.id].updates.push({
'_id': armorSource.id, _id: armorSource.id,
'system.armor.current': armorSource.system.armor.current + usedArmorChange 'system.armor.current': armorSource.system.armor.current + usedArmorChange
}); });
} else { } else {
effectUpdates[armorSource.parent.id].updates.push({ effectUpdates[armorSource.parent.id].updates.push({
'_id': armorSource.id, _id: armorSource.id,
'system.changes': armorSource.system.changes.map(change => ({ 'system.changes': armorSource.system.changes.map(change => ({
...change, ...change,
value: value:
change.type === 'armor' change.type === 'armor'
? { ? {
...change.value, ...change.value,
current: armorSource.system.armorChange.value.current + usedArmorChange current: armorSource.system.armorChange.value.current + usedArmorChange
} }
: change.value : change.value
})) }))
}); });
@ -621,21 +621,21 @@ export default class DhCharacter extends DhCreature {
}, },
...(multiclassFeatures.length ...(multiclassFeatures.length
? { ? {
multiclassFeatures: { multiclassFeatures: {
title: `${game.i18n.localize('DAGGERHEART.GENERAL.multiclass')} - ${this.multiclass.value?.name}`, title: `${game.i18n.localize('DAGGERHEART.GENERAL.multiclass')} - ${this.multiclass.value?.name}`,
type: 'multiclass', type: 'multiclass',
values: multiclassFeatures values: multiclassFeatures
} }
} }
: {}), : {}),
...(multiclassSubclassFeatures.length ...(multiclassSubclassFeatures.length
? { ? {
multiclassSubclassFeatures: { multiclassSubclassFeatures: {
title: `${game.i18n.localize('DAGGERHEART.GENERAL.multiclass')} ${game.i18n.localize('TYPES.Item.subclass')} - ${this.multiclass.subclass?.name}`, title: `${game.i18n.localize('DAGGERHEART.GENERAL.multiclass')} ${game.i18n.localize('TYPES.Item.subclass')} - ${this.multiclass.subclass?.name}`,
type: 'multiclassSubclass', type: 'multiclassSubclass',
values: multiclassSubclassFeatures values: multiclassSubclassFeatures
} }
} }
: {}), : {}),
companionFeatures: { companionFeatures: {
title: game.i18n.localize('DAGGERHEART.ACTORS.Character.companionFeatures'), title: game.i18n.localize('DAGGERHEART.ACTORS.Character.companionFeatures'),
@ -659,8 +659,8 @@ export default class DhCharacter extends DhCreature {
(this.primaryWeapon && this.secondaryWeapon) (this.primaryWeapon && this.secondaryWeapon)
? burden.twoHanded.value ? burden.twoHanded.value
: this.primaryWeapon || this.secondaryWeapon : this.primaryWeapon || this.secondaryWeapon
? burden.oneHanded.value ? burden.oneHanded.value
: null; : null;
} }
get deathMoveViable() { get deathMoveViable() {
@ -726,8 +726,8 @@ export default class DhCharacter extends DhCreature {
currentLevel === 1 currentLevel === 1
? null ? null
: Object.values(game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers).find( : Object.values(game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers).find(
tier => currentLevel >= tier.levels.start && currentLevel <= tier.levels.end tier => currentLevel >= tier.levels.start && currentLevel <= tier.levels.end
).tier; ).tier;
if (game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto) { if (game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto) {
for (let levelKey in this.levelData.levelups) { for (let levelKey in this.levelData.levelups) {
const level = this.levelData.levelups[levelKey]; const level = this.levelData.levelups[levelKey];

View file

@ -1,5 +1,6 @@
import { calculateExpectedValue, parseTermsFromSimpleFormula } from '../../helpers/utils.mjs'; import { calculateExpectedValue, parseTermsFromSimpleFormula } from '../../helpers/utils.mjs';
import { adversaryExpectedDamage, adversaryScalingData } from '../../config/actorConfig.mjs'; import { adversaryExpectedDamage, adversaryScalingData } from '../../config/actorConfig.mjs';
import { parseInlineParams } from '../../enrichers/parser.mjs';
export function getTierAdjustedAdversary(source, tier) { export function getTierAdjustedAdversary(source, tier) {
const currentTier = source.tier ?? 1; const currentTier = source.tier ?? 1;
@ -60,8 +61,8 @@ export function getTierAdjustedAdversary(source, tier) {
const descriptionFormulas = []; const descriptionFormulas = [];
for (const withDescription of [item.system, ...Object.values(item.system.actions)]) { for (const withDescription of [item.system, ...Object.values(item.system.actions)]) {
withDescription.description = withDescription.description.replace(damageRegex, (match, inner) => { withDescription.description = withDescription.description.replace(damageRegex, (match, inner) => {
const { value: formula } = parseInlineParams(inner); const { value: formula } = parseInlineParams(inner, { first: 'value' });
if (!formula || !type) return match; if (!formula) return match;
try { try {
const newFormula = calculateAdjustedDamage(formula, 'action', damageMeta)?.formula; const newFormula = calculateAdjustedDamage(formula, 'action', damageMeta)?.formula;

View file

@ -22,12 +22,12 @@ export class DhCompanionLevelup extends foundry.abstract.DataModel {
const initialAchievements = i === tier.levels.start ? tier.initialAchievements : {}; const initialAchievements = i === tier.levels.start ? tier.initialAchievements : {};
const experiences = initialAchievements.experience const experiences = initialAchievements.experience
? [...Array(initialAchievements.experience.nr).keys()].reduce((acc, _) => { ? [...Array(initialAchievements.experience.nr).keys()].reduce((acc, _) => {
acc[foundry.utils.randomID()] = { acc[foundry.utils.randomID()] = {
name: '', name: '',
modifier: initialAchievements.experience.modifier modifier: initialAchievements.experience.modifier
}; };
return acc; return acc;
}, {}) }, {})
: {}; : {};
const currentChoices = pcLevelData.levelups[i]?.selections?.length; const currentChoices = pcLevelData.levelups[i]?.selections?.length;
@ -302,9 +302,9 @@ export class DhLevelupLevel extends foundry.abstract.DataModel {
experiences: levelData.achievements?.experiences ?? achievements.experiences ?? {}, experiences: levelData.achievements?.experiences ?? achievements.experiences ?? {},
domainCards: levelData.achievements?.domainCards domainCards: levelData.achievements?.domainCards
? levelData.achievements.domainCards.reduce((acc, card, index) => { ? levelData.achievements.domainCards.reduce((acc, card, index) => {
acc[index] = { ...card }; acc[index] = { ...card };
return acc; return acc;
}, {}) }, {})
: (achievements.domainCards ?? {}), : (achievements.domainCards ?? {}),
proficiency: levelData.achievements?.proficiency ?? achievements.proficiency ?? null proficiency: levelData.achievements?.proficiency ?? achievements.proficiency ?? null
}, },

View file

@ -77,11 +77,11 @@ export class DhCountdown extends foundry.abstract.DataModel {
static defaultCountdown(type, playerHidden) { static defaultCountdown(type, playerHidden) {
const ownership = playerHidden const ownership = playerHidden
? game.users.reduce((acc, user) => { ? game.users.reduce((acc, user) => {
if (!user.isGM) { if (!user.isGM) {
acc[user.id] = CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE; acc[user.id] = CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE;
} }
return acc; return acc;
}, {}) }, {})
: undefined; : undefined;
return { return {
@ -102,8 +102,8 @@ export class DhCountdown extends foundry.abstract.DataModel {
value: user.isGM value: user.isGM
? CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER ? CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER
: this.ownership.players[user.id] && this.ownership.players[user.id].type !== -1 : this.ownership.players[user.id] && this.ownership.players[user.id].type !== -1
? this.ownership.players[user.id].type ? this.ownership.players[user.id].type
: this.ownership.default, : this.ownership.default,
isGM: user.isGM isGM: user.isGM
}; };

View file

@ -105,8 +105,8 @@ export default class BeastformField extends fields.SchemaField {
baseSize === 'custom' baseSize === 'custom'
? 'custom' ? 'custom'
: (Object.keys(CONFIG.DH.ACTOR.tokenSize).find( : (Object.keys(CONFIG.DH.ACTOR.tokenSize).find(
x => CONFIG.DH.ACTOR.tokenSize[x].value === CONFIG.DH.ACTOR.tokenSize[baseSize].value + 1 x => CONFIG.DH.ACTOR.tokenSize[x].value === CONFIG.DH.ACTOR.tokenSize[baseSize].value + 1
) ?? baseSize); ) ?? baseSize);
formData.system.tokenSize = { formData.system.tokenSize = {
...evolvedData.form.system.tokenSize, ...evolvedData.form.system.tokenSize,
size: evolvedSize size: evolvedSize

View file

@ -116,8 +116,8 @@ export default class CostField extends fields.ArrayField {
c.key === 'fear' c.key === 'fear'
? game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear) ? game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear)
: resources[c.key].isReversed : resources[c.key].isReversed
? resources[c.key].max - resources[c.key].value ? resources[c.key].max - resources[c.key].value
: resources[c.key].value; : resources[c.key].value;
if (c.scalable) c.maxStep = Math.floor((c.max - c.value) / c.step); if (c.scalable) c.maxStep = Math.floor((c.max - c.value) / c.step);
return c; return c;
}); });
@ -149,8 +149,8 @@ export default class CostField extends fields.ArrayField {
!resources[c.key] !resources[c.key]
? a ? a
: a && resources[c.key].isReversed : a && resources[c.key].isReversed
? resources[c.key].value + (c.total ?? c.value) <= resources[c.key].max ? resources[c.key].value + (c.total ?? c.value) <= resources[c.key].max
: resources[c.key]?.value >= (c.total ?? c.value), : resources[c.key]?.value >= (c.total ?? c.value),
true true
); );
} }

View file

@ -87,11 +87,11 @@ export default class CountdownField extends fields.ArrayField {
CONFIG.DH.id, CONFIG.DH.id,
CONFIG.DH.SETTINGS.gameSettings.Countdowns, CONFIG.DH.SETTINGS.gameSettings.Countdowns,
countdownSetting.toObject() countdownSetting.toObject()
), );
game.socket.emit(`system.${CONFIG.DH.id}`, { game.socket.emit(`system.${CONFIG.DH.id}`, {
action: socketEvent.Refresh, action: socketEvent.Refresh,
data: { refreshType: RefreshType.Countdown } data: { refreshType: RefreshType.Countdown }
}); });
Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.Countdown }); Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.Countdown });
}, },
data, data,

View file

@ -61,11 +61,11 @@ export default class EffectsField extends fields.ArrayField {
token: messageToken, token: messageToken,
conditionImmunities: Object.values(conditionImmunities).some(x => x) conditionImmunities: Object.values(conditionImmunities).some(x => x)
? game.i18n.format('DAGGERHEART.UI.Chat.effectSummary.immunityTo', { ? game.i18n.format('DAGGERHEART.UI.Chat.effectSummary.immunityTo', {
immunities: Object.keys(conditionImmunities) immunities: Object.keys(conditionImmunities)
.filter(x => conditionImmunities[x]) .filter(x => conditionImmunities[x])
.map(x => game.i18n.localize(conditions[x].name)) .map(x => game.i18n.localize(conditions[x].name))
.join(', ') .join(', ')
}) })
: null : null
}); });

View file

@ -69,11 +69,11 @@ export default class SaveField extends fields.SchemaField {
game.user === actor.owner game.user === actor.owner
? SaveField.rollSave.call(this, actor, event) ? SaveField.rollSave.call(this, actor, event)
: actor.owner.query('reactionRoll', { : actor.owner.query('reactionRoll', {
actionId: this.uuid, actionId: this.uuid,
actorId: actor.uuid, actorId: actor.uuid,
event, event,
message message
}); });
const result = await rollSave; const result = await rollSave;
await SaveField.updateSaveMessage.call(this, result, message, target.id); await SaveField.updateSaveMessage.call(this, result, message, target.id);
subResolve(); subResolve();
@ -97,8 +97,8 @@ export default class SaveField extends fields.SchemaField {
const title = actor.isNPC const title = actor.isNPC
? game.i18n.localize('DAGGERHEART.GENERAL.reactionRoll') ? game.i18n.localize('DAGGERHEART.GENERAL.reactionRoll')
: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { : game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', {
ability: game.i18n.localize(abilities[this.save.trait]?.label) ability: game.i18n.localize(abilities[this.save.trait]?.label)
}), }),
rollConfig = { rollConfig = {
event, event,
title, title,

View file

@ -1,6 +1,6 @@
import BaseDataItem from './base.mjs'; import BaseDataItem from './base.mjs';
import ItemLinkFields from '../../data/fields/itemLinkFields.mjs'; import ItemLinkFields from '../../data/fields/itemLinkFields.mjs';
import { getFeaturesHTMLData } from '../../helpers/utils.mjs'; import { fromUuids, getFeaturesHTMLData } from '../../helpers/utils.mjs';
export default class DHAncestry extends BaseDataItem { export default class DHAncestry extends BaseDataItem {
/** @inheritDoc */ /** @inheritDoc */
@ -45,6 +45,10 @@ export default class DHAncestry extends BaseDataItem {
/**@inheritdoc */ /**@inheritdoc */
async getDescriptionData() { async getDescriptionData() {
// Preload all ancestry features for acquisition from the cache
// todo: make feature acquisition async and replace feature helpers for methods
await fromUuids(this._source.features.map(f => f.item));
const baseDescription = this.description; const baseDescription = this.description;
const features = await getFeaturesHTMLData(this.features); const features = await getFeaturesHTMLData(this.features);

View file

@ -208,8 +208,8 @@ export default class DHBeastform extends BaseDataItem {
const autoTokenSize = const autoTokenSize =
this.tokenSize.size !== 'custom' this.tokenSize.size !== 'custom'
? game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).tokenSizes[ ? game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).tokenSizes[
this.tokenSize.size this.tokenSize.size
] ]
: null; : null;
const width = autoTokenSize ?? this.tokenSize.width; const width = autoTokenSize ?? this.tokenSize.width;
const height = autoTokenSize ?? this.tokenSize.height; const height = autoTokenSize ?? this.tokenSize.height;

View file

@ -1,4 +1,4 @@
import { getFeaturesHTMLData } from '../../helpers/utils.mjs'; import { fromUuids, getFeaturesHTMLData } from '../../helpers/utils.mjs';
import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs'; import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs';
import BaseDataItem from './base.mjs'; import BaseDataItem from './base.mjs';
@ -27,6 +27,10 @@ export default class DHCommunity extends BaseDataItem {
/**@inheritdoc */ /**@inheritdoc */
async getDescriptionData() { async getDescriptionData() {
// Preload all community features for acquisition from the cache
// todo: make feature acquisition async and replace feature helpers for methods
await fromUuids(this._source.features);
const baseDescription = this.description; const baseDescription = this.description;
const features = await getFeaturesHTMLData(this.features); const features = await getFeaturesHTMLData(this.features);

View file

@ -91,7 +91,7 @@ export default class DHSubclass extends BaseDataItem {
? game.i18n.localize(CONFIG.DH.ACTOR.abilities[this.spellcastingTrait].label) ? game.i18n.localize(CONFIG.DH.ACTOR.abilities[this.spellcastingTrait].label)
: null; : null;
// Preload all class features for acquisition from the cache // Preload all subclass features for acquisition from the cache
// todo: make feature acquisition async and replace feature helpers for methods // todo: make feature acquisition async and replace feature helpers for methods
await fromUuids(this._source.features.map(f => f.item)); await fromUuids(this._source.features.map(f => f.item));

View file

@ -19,12 +19,12 @@ export class DhLevelup extends foundry.abstract.DataModel {
const initialAchievements = i === tier.levels.start ? tier.initialAchievements : {}; const initialAchievements = i === tier.levels.start ? tier.initialAchievements : {};
const experiences = initialAchievements.experience const experiences = initialAchievements.experience
? [...Array(initialAchievements.experience.nr).keys()].reduce((acc, _) => { ? [...Array(initialAchievements.experience.nr).keys()].reduce((acc, _) => {
acc[foundry.utils.randomID()] = { acc[foundry.utils.randomID()] = {
name: '', name: '',
modifier: initialAchievements.experience.modifier modifier: initialAchievements.experience.modifier
}; };
return acc; return acc;
}, {}) }, {})
: {}; : {};
const domainCards = [...Array(tier.domainCardByLevel).keys()].reduce((acc, _) => { const domainCards = [...Array(tier.domainCardByLevel).keys()].reduce((acc, _) => {
@ -298,9 +298,9 @@ export class DhLevelupLevel extends foundry.abstract.DataModel {
experiences: levelData.achievements?.experiences ?? achievements.experiences ?? {}, experiences: levelData.achievements?.experiences ?? achievements.experiences ?? {},
domainCards: levelData.achievements?.domainCards domainCards: levelData.achievements?.domainCards
? levelData.achievements.domainCards.reduce((acc, card, index) => { ? levelData.achievements.domainCards.reduce((acc, card, index) => {
acc[index] = { ...card }; acc[index] = { ...card };
return acc; return acc;
}, {}) }, {})
: (achievements.domainCards ?? {}), : (achievements.domainCards ?? {}),
proficiency: levelData.achievements?.proficiency ?? achievements.proficiency ?? null proficiency: levelData.achievements?.proficiency ?? achievements.proficiency ?? null
}, },

View file

@ -37,6 +37,7 @@ export default class DHRoll extends Roll {
static async buildConfigure(config = {}, message = {}) { static async buildConfigure(config = {}, message = {}) {
config.hooks = [...this.getHooks(), '']; config.hooks = [...this.getHooks(), ''];
config.dialog ??= {}; config.dialog ??= {};
config.damageOptions ??= {};
for (const hook of config.hooks) { for (const hook of config.hooks) {
if (Hooks.call(`${CONFIG.DH.id}.preRoll${hook.capitalize()}`, config, message) === false) return null; if (Hooks.call(`${CONFIG.DH.id}.preRoll${hook.capitalize()}`, config, message) === false) return null;
@ -103,9 +104,9 @@ export default class DHRoll extends Roll {
if (action?.chatDisplay) { if (action?.chatDisplay) {
actionDescription = action actionDescription = action
? await foundry.applications.ux.TextEditor.implementation.enrichHTML(action.description, { ? await foundry.applications.ux.TextEditor.implementation.enrichHTML(action.description, {
relativeTo: config.data, relativeTo: config.data,
rollData: config.data.getRollData?.() ?? {} rollData: config.data.getRollData?.() ?? {}
}) })
: null; : null;
config.actionChatMessageHandled = true; config.actionChatMessageHandled = true;
} }

View file

@ -109,10 +109,10 @@ export default class DualityRoll extends D20Roll {
const label = this.guaranteedCritical const label = this.guaranteedCritical
? 'DAGGERHEART.GENERAL.guaranteedCriticalSuccess' ? 'DAGGERHEART.GENERAL.guaranteedCriticalSuccess'
: this.isCritical : this.isCritical
? 'DAGGERHEART.GENERAL.criticalSuccess' ? 'DAGGERHEART.GENERAL.criticalSuccess'
: this.withHope : this.withHope
? 'DAGGERHEART.GENERAL.hope' ? 'DAGGERHEART.GENERAL.hope'
: 'DAGGERHEART.GENERAL.fear'; : 'DAGGERHEART.GENERAL.fear';
return game.i18n.localize(label); return game.i18n.localize(label);
} }
@ -147,8 +147,8 @@ export default class DualityRoll extends D20Roll {
const advDieClass = this.hasAdvantage const advDieClass = this.hasAdvantage
? game.system.api.dice.diceTypes.AdvantageDie ? game.system.api.dice.diceTypes.AdvantageDie
: this.hasDisadvantage : this.hasDisadvantage
? game.system.api.dice.diceTypes.DisadvantageDie ? game.system.api.dice.diceTypes.DisadvantageDie
: null; : null;
if (advDieClass) { if (advDieClass) {
const advDie = new advDieClass({ faces: this.advantageFaces, number: this.advantageNumber }); const advDie = new advDieClass({ faces: this.advantageFaces, number: this.advantageNumber });
if (this.terms.length < 4) { if (this.terms.length < 4) {

View file

@ -1,3 +1,5 @@
import { ResourceUpdateMap } from '../data/action/baseAction.mjs';
export function updateResourcesForDualityReroll(oldDuality, newDuality, actor) { export function updateResourcesForDualityReroll(oldDuality, newDuality, actor) {
const { hopeFear } = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation); const { hopeFear } = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation);
if (game.user.isGM ? !hopeFear.gm : !hopeFear.players) return; if (game.user.isGM ? !hopeFear.gm : !hopeFear.players) return;

View file

@ -175,8 +175,8 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect {
return model instanceof documentClass return model instanceof documentClass
? model ? model
: model.parent : model.parent
? this.#resolveParentDocument(model.parent, documentClass) ? this.#resolveParentDocument(model.parent, documentClass)
: null; : null;
} }
static getChangeValue(model, change, effect) { static getChangeValue(model, change, effect) {

View file

@ -9,9 +9,9 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
actor && this.isContentVisible actor && this.isContentVisible
? actor ? actor
: { : {
img: this.author.avatar ? this.author.avatar : 'icons/svg/mystery-man.svg', img: this.author.avatar ? this.author.avatar : 'icons/svg/mystery-man.svg',
name: '' name: ''
}; };
/* We can change to fully implementing the renderHTML function if needed, instead of augmenting it. */ /* We can change to fully implementing the renderHTML function if needed, instead of augmenting it. */
const html = await super.renderHTML({ actor: actorData, author: this.author }); const html = await super.renderHTML({ actor: actorData, author: this.author });
@ -290,14 +290,14 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
behaviors: behaviors:
effects.length > 0 effects.length > 0
? [ ? [
{ {
name: game.i18n.localize('TYPES.RegionBehavior.applyActiveEffect'), name: game.i18n.localize('TYPES.RegionBehavior.applyActiveEffect'),
type: 'applyActiveEffect', type: 'applyActiveEffect',
system: { system: {
effects: effects effects: effects
} }
} }
] ]
: [], : [],
displayMeasurements: true, displayMeasurements: true,
locked: false, locked: false,

View file

@ -98,8 +98,8 @@ export default class DHItem extends foundry.documents.Item {
isInventoryItem === true isInventoryItem === true
? 'Inventory Items' //TODO localize ? 'Inventory Items' //TODO localize
: isInventoryItem === false : isInventoryItem === false
? 'Character Items' //TODO localize ? 'Character Items' //TODO localize
: 'Other'; //TODO localize : 'Other'; //TODO localize
return { value: type, label, group }; return { value: type, label, group };
} }

View file

@ -324,7 +324,7 @@ export default class DHToken extends CONFIG.Token.documentClass {
} }
let x = 0.5 * bottom; let x = 0.5 * bottom;
let y = 0.25; let y = 0.25;
for (let k = width - bottom; k--; ) { for (let k = width - bottom; k--;) {
points.push(x, y); points.push(x, y);
x += 0.5; x += 0.5;
y -= 0.25; y -= 0.25;
@ -333,7 +333,7 @@ export default class DHToken extends CONFIG.Token.documentClass {
y += 0.25; y += 0.25;
} }
points.push(x, y); points.push(x, y);
for (let k = bottom; k--; ) { for (let k = bottom; k--;) {
y += 0.5; y += 0.5;
points.push(x, y); points.push(x, y);
x += 0.5; x += 0.5;
@ -341,14 +341,14 @@ export default class DHToken extends CONFIG.Token.documentClass {
points.push(x, y); points.push(x, y);
} }
y += 0.5; y += 0.5;
for (let k = top; k--; ) { for (let k = top; k--;) {
points.push(x, y); points.push(x, y);
x -= 0.5; x -= 0.5;
y += 0.25; y += 0.25;
points.push(x, y); points.push(x, y);
y += 0.5; y += 0.5;
} }
for (let k = width - top; k--; ) { for (let k = width - top; k--;) {
points.push(x, y); points.push(x, y);
x -= 0.5; x -= 0.5;
y += 0.25; y += 0.25;
@ -357,7 +357,7 @@ export default class DHToken extends CONFIG.Token.documentClass {
y -= 0.25; y -= 0.25;
} }
points.push(x, y); points.push(x, y);
for (let k = top; k--; ) { for (let k = top; k--;) {
y -= 0.5; y -= 0.5;
points.push(x, y); points.push(x, y);
x -= 0.5; x -= 0.5;
@ -365,7 +365,7 @@ export default class DHToken extends CONFIG.Token.documentClass {
points.push(x, y); points.push(x, y);
} }
y -= 0.5; y -= 0.5;
for (let k = bottom; k--; ) { for (let k = bottom; k--;) {
points.push(x, y); points.push(x, y);
x += 0.5; x += 0.5;
y -= 0.25; y -= 0.25;

View file

@ -1,7 +1,7 @@
import { parseInlineParams } from './parser.mjs'; import { parseInlineParams } from './parser.mjs';
export default function DhDamageEnricher(match, _options) { export default function DhDamageEnricher(match, _options) {
const { value, type, inline } = parseInlineParams(match[1]); const { value, type, inline } = parseInlineParams(match[1], { first: 'value' });
if (!value || !type) return match[0]; if (!value || !type) return match[0];
return getDamageMessage(value, type, inline, match[0]); return getDamageMessage(value, type, inline, match[0]);
} }
@ -59,7 +59,7 @@ export const renderDamageButton = async event => {
{ {
formula: value, formula: value,
applyTo: CONFIG.DH.GENERAL.healingTypes.hitPoints.id, applyTo: CONFIG.DH.GENERAL.healingTypes.hitPoints.id,
type: type damageTypes: type
} }
] ]
}; };

View file

@ -15,8 +15,8 @@ function getDualityMessage(roll, flavor) {
(roll?.trait (roll?.trait
? game.i18n.format('DAGGERHEART.GENERAL.rollWith', { roll: trait }) ? game.i18n.format('DAGGERHEART.GENERAL.rollWith', { roll: trait })
: roll?.reaction : roll?.reaction
? game.i18n.localize('DAGGERHEART.GENERAL.reactionRoll') ? game.i18n.localize('DAGGERHEART.GENERAL.reactionRoll')
: game.i18n.localize('DAGGERHEART.GENERAL.duality')); : game.i18n.localize('DAGGERHEART.GENERAL.duality'));
const dataLabel = trait const dataLabel = trait
? game.i18n.localize(abilities[roll.trait].label) ? game.i18n.localize(abilities[roll.trait].label)
@ -25,14 +25,14 @@ function getDualityMessage(roll, flavor) {
const advantage = roll?.advantage const advantage = roll?.advantage
? CONFIG.DH.ACTIONS.advantageState.advantage.value ? CONFIG.DH.ACTIONS.advantageState.advantage.value
: roll?.disadvantage : roll?.disadvantage
? CONFIG.DH.ACTIONS.advantageState.disadvantage.value ? CONFIG.DH.ACTIONS.advantageState.disadvantage.value
: undefined; : undefined;
const advantageLabel = const advantageLabel =
advantage === CONFIG.DH.ACTIONS.advantageState.advantage.value advantage === CONFIG.DH.ACTIONS.advantageState.advantage.value
? 'Advantage' ? 'Advantage'
: advantage === CONFIG.DH.ACTIONS.advantageState.disadvantage.value : advantage === CONFIG.DH.ACTIONS.advantageState.disadvantage.value
? 'Disadvantage' ? 'Disadvantage'
: undefined; : undefined;
const dualityElement = document.createElement('span'); const dualityElement = document.createElement('span');
dualityElement.innerHTML = ` dualityElement.innerHTML = `

View file

@ -8,8 +8,8 @@ export default function DhTemplateEnricher(match, _options) {
const range = const range =
params.range && Number.isNaN(Number(params.range)) params.range && Number.isNaN(Number(params.range))
? Object.values(CONFIG.DH.GENERAL.templateRanges).find( ? Object.values(CONFIG.DH.GENERAL.templateRanges).find(
x => x.id.toLowerCase() === params.range || x.short === params.range x => x.id.toLowerCase() === params.range || x.short === params.range
)?.id )?.id
: params.range; : params.range;
if (!CONFIG.DH.GENERAL.templateTypes[type] || !range) return match[0]; if (!CONFIG.DH.GENERAL.templateTypes[type] || !range) return match[0];

View file

@ -8,7 +8,7 @@ export function parseInlineParams(paramString, { first } = {}) {
const parts = paramString.split('|').map(x => x.trim()); const parts = paramString.split('|').map(x => x.trim());
const params = {}; const params = {};
for (const [idx, param] of parts.entries()) { for (const [idx, param] of parts.entries()) {
if (first && idx === 0) { if (first && idx === 0 && !param.includes(':')) {
params[first] = param; params[first] = param;
} else { } else {
const parts = param.split(':'); const parts = param.split(':');

View file

@ -108,9 +108,9 @@ export const tagifyElement = (element, baseOptions, onChange, tagifyOptions = {}
const options = Array.isArray(baseOptions) const options = Array.isArray(baseOptions)
? baseOptions ? baseOptions
: Object.keys(baseOptions).map(optionKey => ({ : Object.keys(baseOptions).map(optionKey => ({
...baseOptions[optionKey], ...baseOptions[optionKey],
id: optionKey id: optionKey
})); }));
const tagifyElement = new Tagify(element, { const tagifyElement = new Tagify(element, {
tagTextProp: 'name', tagTextProp: 'name',
@ -605,8 +605,8 @@ export function calculateExpectedValue(formulaOrTerms) {
const terms = Array.isArray(formulaOrTerms) const terms = Array.isArray(formulaOrTerms)
? formulaOrTerms ? formulaOrTerms
: typeof formulaOrTerms === 'string' : typeof formulaOrTerms === 'string'
? parseTermsFromSimpleFormula(formulaOrTerms) ? parseTermsFromSimpleFormula(formulaOrTerms)
: [formulaOrTerms]; : [formulaOrTerms];
return terms.reduce((r, t) => r + (t.bonus ?? 0) + (t.diceQuantity ? (t.diceQuantity * (t.faces + 1)) / 2 : 0), 0); return terms.reduce((r, t) => r + (t.bonus ?? 0) + (t.diceQuantity ? (t.diceQuantity * (t.faces + 1)) / 2 : 0), 0);
} }
@ -656,8 +656,8 @@ export async function RefreshFeatures(
'resource.value': increasing 'resource.value': increasing
? 0 ? 0
: game.system.api.documents.DhActiveEffect.effectSafeEval( : game.system.api.documents.DhActiveEffect.effectSafeEval(
Roll.replaceFormulaData(item.system.resource.max, actor.getRollData()) Roll.replaceFormulaData(item.system.resource.max, actor.getRollData())
) )
}; };
} }
if (item.system.metadata?.hasActions) { if (item.system.metadata?.hasActions) {
@ -879,6 +879,7 @@ export async function fromUuids(uuids) {
const packEmbeddedEntries = entries.filter( const packEmbeddedEntries = entries.filter(
e => e =>
!(e.value instanceof Document) && !(e.value instanceof Document) &&
e.parsed &&
e.parsed.collection instanceof foundry.documents.collections.CompendiumCollection && e.parsed.collection instanceof foundry.documents.collections.CompendiumCollection &&
e.parsed.embedded.length > 0 e.parsed.embedded.length > 0
); );
@ -895,7 +896,7 @@ export async function fromUuids(uuids) {
const pack = game.packs.get(packGroup[0].value.pack); const pack = game.packs.get(packGroup[0].value.pack);
if (!pack) continue; if (!pack) continue;
const ids = packGroup.map(p => p.parsed.id); const ids = packGroup.map(p => p.parsed?.id).filter(id => !!id);
const documents = await pack.getDocuments({ _id__in: ids }); const documents = await pack.getDocuments({ _id__in: ids });
for (const p of packGroup) { for (const p of packGroup) {
p.value = documents.find(d => d.id === p.parsed.id) ?? p.value; p.value = documents.find(d => d.id === p.parsed.id) ?? p.value;

View file

@ -24,8 +24,8 @@ export async function runMigrations() {
const { originItemType, isMulticlass, identifier } = item.system; const { originItemType, isMulticlass, identifier } = item.system;
const base = originItemType const base = originItemType
? actor.items.find( ? actor.items.find(
x => x.type === originItemType && Boolean(isMulticlass) === Boolean(x.system.isMulticlass) x => x.type === originItemType && Boolean(isMulticlass) === Boolean(x.system.isMulticlass)
) )
: null; : null;
if (base) { if (base) {
const feature = base.system.features.find(x => x.item && x.item.uuid === item.uuid); const feature = base.system.features.find(x => x.item && x.item.uuid === item.uuid);

551
package-lock.json generated
View file

@ -13,18 +13,20 @@
"rollup": "^4.40.0" "rollup": "^4.40.0"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^10.0.1",
"@foundryvtt/foundryvtt-cli": "^1.0.2", "@foundryvtt/foundryvtt-cli": "^1.0.2",
"@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-node-resolve": "^15.2.3",
"@stylistic/eslint-plugin": "^5.10.0",
"concurrently": "^8.2.2", "concurrently": "^8.2.2",
"eslint": "^10.2.1", "eslint": "^10.2.1",
"eslint-plugin-prettier": "^5.5.5",
"globals": "^17.5.0", "globals": "^17.5.0",
"husky": "^9.1.7", "husky": "^9.1.7",
"lint-staged": "^16.4.0", "lint-staged": "^16.4.0",
"postcss": "^8.4.32", "postcss": "^8.4.32",
"prettier": "^3.5.3", "rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-postcss": "^4.0.2" "typescript": "^6.0.3",
"typescript-eslint": "^8.60.1"
} }
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
@ -158,6 +160,27 @@
"node": "^20.19.0 || ^22.13.0 || >=24" "node": "^20.19.0 || ^22.13.0 || >=24"
} }
}, },
"node_modules/@eslint/js": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz",
"integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
"url": "https://eslint.org/donate"
},
"peerDependencies": {
"eslint": "^10.0.0"
},
"peerDependenciesMeta": {
"eslint": {
"optional": true
}
}
},
"node_modules/@eslint/object-schema": { "node_modules/@eslint/object-schema": {
"version": "3.0.5", "version": "3.0.5",
"resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz",
@ -420,19 +443,6 @@
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
"dev": true "dev": true
}, },
"node_modules/@pkgr/core": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
"integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/pkgr"
}
},
"node_modules/@rollup/plugin-commonjs": { "node_modules/@rollup/plugin-commonjs": {
"version": "25.0.8", "version": "25.0.8",
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.8.tgz", "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.8.tgz",
@ -761,6 +771,58 @@
"util": "^0.12.4" "util": "^0.12.4"
} }
}, },
"node_modules/@stylistic/eslint-plugin": {
"version": "5.10.0",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.10.0.tgz",
"integrity": "sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.9.1",
"@typescript-eslint/types": "^8.56.0",
"eslint-visitor-keys": "^4.2.1",
"espree": "^10.4.0",
"estraverse": "^5.3.0",
"picomatch": "^4.0.3"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"peerDependencies": {
"eslint": "^9.0.0 || ^10.0.0"
}
},
"node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@stylistic/eslint-plugin/node_modules/espree": {
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
"integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"acorn": "^8.15.0",
"acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^4.2.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@trysound/sax": { "node_modules/@trysound/sax": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
@ -795,6 +857,288 @@
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
"dev": true "dev": true
}, },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.60.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.1.tgz",
"integrity": "sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.12.2",
"@typescript-eslint/scope-manager": "8.60.1",
"@typescript-eslint/type-utils": "8.60.1",
"@typescript-eslint/utils": "8.60.1",
"@typescript-eslint/visitor-keys": "8.60.1",
"ignore": "^7.0.5",
"natural-compare": "^1.4.0",
"ts-api-utils": "^2.5.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"@typescript-eslint/parser": "^8.60.1",
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
"version": "7.0.5",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
"integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 4"
}
},
"node_modules/@typescript-eslint/parser": {
"version": "8.60.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.60.1.tgz",
"integrity": "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/scope-manager": "8.60.1",
"@typescript-eslint/types": "8.60.1",
"@typescript-eslint/typescript-estree": "8.60.1",
"@typescript-eslint/visitor-keys": "8.60.1",
"debug": "^4.4.3"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/project-service": {
"version": "8.60.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz",
"integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.60.1",
"@typescript-eslint/types": "^8.60.1",
"debug": "^4.4.3"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "8.60.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz",
"integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.60.1",
"@typescript-eslint/visitor-keys": "8.60.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.60.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz",
"integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "8.60.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.1.tgz",
"integrity": "sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.60.1",
"@typescript-eslint/typescript-estree": "8.60.1",
"@typescript-eslint/utils": "8.60.1",
"debug": "^4.4.3",
"ts-api-utils": "^2.5.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/types": {
"version": "8.60.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz",
"integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "8.60.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz",
"integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/project-service": "8.60.1",
"@typescript-eslint/tsconfig-utils": "8.60.1",
"@typescript-eslint/types": "8.60.1",
"@typescript-eslint/visitor-keys": "8.60.1",
"debug": "^4.4.3",
"minimatch": "^10.2.2",
"semver": "^7.7.3",
"tinyglobby": "^0.2.15",
"ts-api-utils": "^2.5.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "18 || 20 || >=22"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
"integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
},
"engines": {
"node": "18 || 20 || >=22"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
"version": "10.2.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
"integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
"brace-expansion": "^5.0.5"
},
"engines": {
"node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.2.tgz",
"integrity": "sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@typescript-eslint/utils": {
"version": "8.60.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz",
"integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.9.1",
"@typescript-eslint/scope-manager": "8.60.1",
"@typescript-eslint/types": "8.60.1",
"@typescript-eslint/typescript-estree": "8.60.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "8.60.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz",
"integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.60.1",
"eslint-visitor-keys": "^5.0.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@yaireo/tagify": { "node_modules/@yaireo/tagify": {
"version": "4.35.1", "version": "4.35.1",
"resolved": "https://registry.npmjs.org/@yaireo/tagify/-/tagify-4.35.1.tgz", "resolved": "https://registry.npmjs.org/@yaireo/tagify/-/tagify-4.35.1.tgz",
@ -1853,10 +2197,11 @@
} }
}, },
"node_modules/debug": { "node_modules/debug": {
"version": "4.4.1", "version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"ms": "^2.1.3" "ms": "^2.1.3"
}, },
@ -2241,37 +2586,6 @@
} }
} }
}, },
"node_modules/eslint-plugin-prettier": {
"version": "5.5.5",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz",
"integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==",
"dev": true,
"license": "MIT",
"dependencies": {
"prettier-linter-helpers": "^1.0.1",
"synckit": "^0.11.12"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint-plugin-prettier"
},
"peerDependencies": {
"@types/eslint": ">=8.0.0",
"eslint": ">=8.0.0",
"eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0",
"prettier": ">=3.0.0"
},
"peerDependenciesMeta": {
"@types/eslint": {
"optional": true
},
"eslint-config-prettier": {
"optional": true
}
}
},
"node_modules/eslint-scope": { "node_modules/eslint-scope": {
"version": "9.1.2", "version": "9.1.2",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz",
@ -2511,13 +2825,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/fast-diff": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
"integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/fast-fifo": { "node_modules/fast-fifo": {
"version": "1.3.2", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
@ -2554,6 +2861,24 @@
"reusify": "^1.0.4" "reusify": "^1.0.4"
} }
}, },
"node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/file-entry-cache": { "node_modules/file-entry-cache": {
"version": "8.0.0", "version": "8.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@ -5217,34 +5542,6 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/prettier": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"dev": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prettier-linter-helpers": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz",
"integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-diff": "^1.1.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/process-nextick-args": { "node_modules/process-nextick-args": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@ -6053,22 +6350,6 @@
"node": ">= 10" "node": ">= 10"
} }
}, },
"node_modules/synckit": {
"version": "0.11.12",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz",
"integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@pkgr/core": "^0.2.9"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/synckit"
}
},
"node_modules/teex": { "node_modules/teex": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz",
@ -6116,6 +6397,23 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/tinyglobby": {
"version": "0.2.17",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
"integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
"dev": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
"picomatch": "^4.0.4"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
"node_modules/to-regex-range": { "node_modules/to-regex-range": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@ -6147,6 +6445,19 @@
"tree-kill": "cli.js" "tree-kill": "cli.js"
} }
}, },
"node_modules/ts-api-utils": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
"integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18.12"
},
"peerDependencies": {
"typescript": ">=4.8.4"
}
},
"node_modules/tslib": { "node_modules/tslib": {
"version": "2.8.1", "version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
@ -6171,6 +6482,44 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/typescript": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/typescript-eslint": {
"version": "8.60.1",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.60.1.tgz",
"integrity": "sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/eslint-plugin": "8.60.1",
"@typescript-eslint/parser": "8.60.1",
"@typescript-eslint/typescript-estree": "8.60.1",
"@typescript-eslint/utils": "8.60.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.1.0"
}
},
"node_modules/unc-path-regex": { "node_modules/unc-path-regex": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",

View file

@ -24,18 +24,20 @@
"prepare": "husky" "prepare": "husky"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^10.0.1",
"@foundryvtt/foundryvtt-cli": "^1.0.2", "@foundryvtt/foundryvtt-cli": "^1.0.2",
"@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-node-resolve": "^15.2.3",
"@stylistic/eslint-plugin": "^5.10.0",
"concurrently": "^8.2.2", "concurrently": "^8.2.2",
"eslint": "^10.2.1", "eslint": "^10.2.1",
"eslint-plugin-prettier": "^5.5.5",
"globals": "^17.5.0", "globals": "^17.5.0",
"husky": "^9.1.7", "husky": "^9.1.7",
"lint-staged": "^16.4.0", "lint-staged": "^16.4.0",
"postcss": "^8.4.32", "postcss": "^8.4.32",
"prettier": "^3.5.3", "rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-postcss": "^4.0.2" "typescript": "^6.0.3",
"typescript-eslint": "^8.60.1"
}, },
"lint-staged": { "lint-staged": {
"**/*": "eslint --fix" "**/*": "eslint --fix"

View file

@ -1,19 +1,11 @@
@import './less/sheets/index.less'; @import './less/sheets/index.less';
@import './less/sheets-settings/index.less'; @import './less/sheets-settings/index.less';
@import './less/dialog/index.less'; @import './less/dialog/index.less';
@import './less/hud/index.less';
@import './less//hud/index.less'; @import './less/utils/index.less';
@import './less/utils/colors.less';
@import './less/utils/fonts.less';
@import './less/global/index.less'; @import './less/global/index.less';
@import './less/ui/index.less'; @import './less/ui/index.less';
@import './less/ux/index.less'; @import './less/ux/index.less';
@import '../build/tagify.css'; @import '../build/tagify.css';
@import './less/utils/mixin.less';

View file

@ -0,0 +1 @@
@import "./action-list.less";

View file

@ -0,0 +1 @@
@import "./sheet.less";

View file

@ -0,0 +1 @@
@import "./sheet.less";

View file

@ -0,0 +1,4 @@
@import "./sheet.less";
@import "./creation-action-footer.less";
@import "./selections-container.less";
@import "./tab-navigation.less";

View file

@ -0,0 +1 @@
@import './sheet.less';

View file

@ -0,0 +1 @@
@import './sheet.less';

View file

@ -0,0 +1,2 @@
@import './sheets.less';
@import './damage-reduction-container.less';

View file

@ -0,0 +1 @@
@import './sheet.less';

View file

@ -0,0 +1 @@
@import './death-move-container.less';

View file

@ -0,0 +1 @@
@import './roll-selection.less';

View file

@ -0,0 +1 @@
@import './downtime-container.less';

View file

@ -1,44 +0,0 @@
h1 {
color: @color-text-emphatic;
font: 700 var(--font-size-24) var(--dh-font-subtitle);
text-align: center;
}
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;
}

View file

@ -1,8 +1,3 @@
.daggerheart.dialog.dh-style.views.group-roll-dialog { @import './sheet.less';
.window-content { @import './initialization.less';
@import "./_common.less"; @import './main.less';
}
}
@import "./initialization.less";
@import "./main.less";

View file

@ -0,0 +1,48 @@
.daggerheart.dialog.dh-style.views.group-roll-dialog {
.window-content {
h1 {
color: @color-text-emphatic;
font: 700 var(--font-size-24) var(--dh-font-subtitle);
text-align: center;
}
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;
}
}
}

View file

@ -0,0 +1 @@
@import './sheet.less';

View file

@ -1,42 +1,20 @@
@import './attribution/sheet.less'; @import './actions/index.less';
@import './level-up/index.less'; @import './attribution/index.less';
@import './beastform/index.less';
@import './resource-dice/sheet.less'; @import './character-creation/index.less';
@import './character-reset/index.less';
@import './actions/action-list.less'; @import './compendiumBrowserPackDialog/index.less';
@import './damage-reduction/index.less';
@import './damage-selection/sheet.less'; @import './damage-selection/index.less';
@import './death-move/index.less';
@import './downtime/downtime-container.less'; @import './dice-roll/index.less';
@import './downtime/index.less';
@import './death-move/death-move-container.less';
@import './beastform/sheet.less';
@import './character-creation/creation-action-footer.less';
@import './character-creation/selections-container.less';
@import './character-creation/sheet.less';
@import './character-creation/tab-navigation.less';
@import './dice-roll/roll-selection.less';
@import './damage-reduction/damage-reduction-container.less';
@import './damage-reduction/sheets.less';
@import './multiclass-choice/sheet.less';
@import './tag-team-dialog/initialization.less';
@import './tag-team-dialog/sheet.less';
@import './group-roll-dialog/index.less'; @import './group-roll-dialog/index.less';
@import './level-up/index.less';
@import './image-select/sheet.less'; @import './resource-dice/index.less';
@import './multiclass-choice/index.less';
@import './item-transfer/sheet.less'; @import './tag-team-dialog/index.less';
@import './image-select/index.less';
@import './settings/change-currency-icon.less'; @import './item-transfer/index.less';
@import './settings/index.less';
@import './risk-it-all/sheet.less'; @import './risk-it-all/index.less';
@import './character-reset/sheet.less';
@import './compendiumBrowserPackDialog/sheet.less';

View file

@ -0,0 +1 @@
@import './sheet.less';

View file

@ -0,0 +1 @@
@import './sheet.less';

View file

@ -0,0 +1 @@
@import './sheet.less';

View file

@ -0,0 +1 @@
@import './sheet.less';

View file

@ -0,0 +1 @@
@import './change-currency-icon.less';

View file

@ -0,0 +1,2 @@
@import './sheet.less';
@import './initialization.less';

View file

@ -1 +1 @@
@import './token-hud/token-hud.less'; @import './token-hud/index.less';

View file

@ -0,0 +1 @@
@import './token-hud.less';

View file

@ -0,0 +1,3 @@
@import './sheet.less';
@import './experiences.less';
@import './features.less';

View file

@ -0,0 +1 @@
@import './sheet.less';

View file

@ -0,0 +1,2 @@
@import './adversaries.less';
@import './features.less';

View file

@ -1,8 +1,4 @@
@import './header.less'; @import './header.less';
@import './adversary-settings/sheet.less'; @import './adversary-settings/index.less';
@import './adversary-settings/experiences.less'; @import './character-settings/index.less';
@import './adversary-settings/features.less'; @import './environment-settings/index.less';
@import './character-settings/sheet.less';
@import './environment-settings/features.less';
@import './environment-settings/adversaries.less';

View file

@ -0,0 +1 @@
@import './actions.less';

View file

@ -0,0 +1 @@
@import './activeEffects.less';

View file

@ -0,0 +1,7 @@
@import './actor-sheet-shared.less';
@import './adversary/index.less';
@import './character/index.less';
@import './companion/index.less';
@import './environment/index.less';
@import './npc/index.less';
@import './party/index.less';

View file

@ -1,22 +1,5 @@
@import './actions/actions.less'; @import './activeEffects/index.less';
@import './actions/index.less';
@import './actors/actor-sheet-shared.less'; @import './actors/index.less';
@import './items/index.less';
@import './actors/adversary/index.less'; @import './rollTables/index.less';
@import './actors/character/index.less';
@import './actors/companion/index.less';
@import './actors/environment/index.less';
@import './actors/npc/index.less';
@import './actors/party/index.less';
@import './items/beastform.less';
@import './items/class.less';
@import './items/domain-card.less';
@import './items/feature.less';
@import './items/heritage.less';
@import './items/item-sheet-shared.less';
@import './rollTables/sheet.less';
@import './actions/actions.less';
@import './activeEffects/activeEffects.less';

View file

@ -0,0 +1,6 @@
@import './beastform.less';
@import './class.less';
@import './domain-card.less';
@import './feature.less';
@import './heritage.less';
@import './item-sheet-shared.less';

View file

@ -0,0 +1 @@
@import './sheet.less';

Some files were not shown because too many files have changed in this diff Show more