Compare commits

..

No commits in common. "main" and "2.3.1" have entirely different histories.
main ... 2.3.1

124 changed files with 834 additions and 1128 deletions

View file

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

13
.prettierrc Normal file
View file

@ -0,0 +1,13 @@
{
"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,10 +66,6 @@ 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,11 +1,8 @@
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.
@ -15,28 +12,9 @@ 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

@ -1,101 +1,14 @@
import globals from 'globals'; import globals from 'globals';
import { defineConfig, globalIgnores } from 'eslint/config'; import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint'; import prettier from 'eslint-plugin-prettier';
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([
globalIgnores(['foundry/**/*', 'build/**/*']), { files: ['**/*.{js,mjs,cjs}'], languageOptions: { globals: globals.browser } },
{ { 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: {
'no-undef': 'error', 'prettier/prettier': '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": "es2022", "module": "ES6",
"target": "es2022", "target": "ES6",
"paths": { "paths": {
"@client/*": ["./foundry/client/*"], "@client/*": ["./foundry/client/*"],
"@common/*": ["./foundry/common/*"] "@common/*": ["./foundry/common/*"]

View file

@ -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

@ -138,12 +138,12 @@ 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: stress.value + selectedStressMarks.length + stressReductionStress, value:
max: stress.max this.actor.system.resources.stress.value + selectedStressMarks.length + stressReductionStress,
max: this.actor.system.resources.stress.max
} }
: null; : null;

View file

@ -135,6 +135,192 @@ 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;
@ -172,14 +358,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,
@ -198,7 +384,9 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
this._dragDrop.forEach(d => d.bind(htmlElement)); this._dragDrop.forEach(d => d.bind(htmlElement));
} }
tagifyUpdate = type => async (_, { option, removed }) => { tagifyUpdate =
type =>
async (_, { option, removed }) => {
const updatePath = Object.keys(this.levelup.levels[this.levelup.currentLevel].choices).reduce( const updatePath = Object.keys(this.levelup.levels[this.levelup.currentLevel].choices).reduce(
(acc, choiceKey) => { (acc, choiceKey) => {
const choice = this.levelup.levels[this.levelup.currentLevel].choices[choiceKey]; const choice = this.levelup.levels[this.levelup.currentLevel].choices[choiceKey];

View file

@ -111,7 +111,7 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
switch (partId) { switch (partId) {
case 'domains': case 'domains':
const selectedDomain = this.settings.domains[this.selected.domain] ?? null; const selectedDomain = this.selected.domain ? 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;

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

@ -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) return; if (!actor || !actor?.isOwner) reject();
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

@ -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,6 +29,16 @@ 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

@ -50,7 +50,7 @@ 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(CONFIG.DH.ACTOR.abilities[traitValue].label) ability: game.i18n.localize(SYSTEM.ACTOR.abilities[traitValue].label)
}) })
: game.i18n.localize('DAGGERHEART.GENERAL.duality'); : game.i18n.localize('DAGGERHEART.GENERAL.duality');

View file

@ -148,7 +148,7 @@ 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 }

View file

@ -31,9 +31,9 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
minimizable: false minimizable: false
}, },
actions: { actions: {
toggleViewMode: DhCountdowns.#onToggleViewMode, toggleViewMode: DhCountdowns.#toggleViewMode,
editCountdowns: DhCountdowns.#onEditCountdowns, editCountdowns: DhCountdowns.#editCountdowns,
loopCountdown: DhCountdowns.#onLoopCountdown, loopCountdown: DhCountdowns.#loopCountdown,
decreaseCountdown: (_, target) => this.editCountdown(false, target), decreaseCountdown: (_, target) => this.editCountdown(false, target),
increaseCountdown: (_, target) => this.editCountdown(true, target) increaseCountdown: (_, target) => this.editCountdown(true, target)
}, },
@ -147,7 +147,7 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
return true; return true;
} }
static async #onToggleViewMode() { static async #toggleViewMode() {
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,16 +158,15 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
this.render(); this.render();
} }
static async #onEditCountdowns() { static async #editCountdowns() {
new game.system.api.applications.ui.CountdownEdit().render(true); new game.system.api.applications.ui.CountdownEdit().render(true);
} }
static async #onLoopCountdown(_, target) { static async #loopCountdown(_, 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 countdownId = target.closest('[data-countdown]').dataset.countdown; const countdown = settings.countdowns[target.id];
const countdown = settings.countdowns[countdownId];
let progressMax = countdown.progress.start; let progressMax = countdown.progress.start;
let message = null; let message = null;
@ -186,7 +185,7 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
await waitForDiceSoNice(message); await waitForDiceSoNice(message);
await settings.updateSource({ await settings.updateSource({
[`countdowns.${countdownId}.progress`]: { [`countdowns.${target.id}.progress`]: {
current: newMax, current: newMax,
start: newMax start: newMax
} }
@ -200,19 +199,18 @@ 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 countdownId = target.closest('[data-countdown]').dataset.countdown; const countdown = settings.countdowns[target.id];
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.${countdownId}.progress.current`]: newCurrent }); await settings.updateSource({ [`countdowns.${target.id}.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 }

View file

@ -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;

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

@ -520,12 +520,12 @@ 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:

View file

@ -1,6 +1,5 @@
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;
@ -61,8 +60,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, { first: 'value' }); const { value: formula } = parseInlineParams(inner);
if (!formula) return match; if (!formula || !type) return match;
try { try {
const newFormula = calculateAdjustedDamage(formula, 'action', damageMeta)?.formula; const newFormula = calculateAdjustedDamage(formula, 'action', damageMeta)?.formula;

View file

@ -87,7 +87,7 @@ 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 }

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 { fromUuids, getFeaturesHTMLData } from '../../helpers/utils.mjs'; import { getFeaturesHTMLData } from '../../helpers/utils.mjs';
export default class DHAncestry extends BaseDataItem { export default class DHAncestry extends BaseDataItem {
/** @inheritDoc */ /** @inheritDoc */
@ -45,10 +45,6 @@ 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

@ -1,4 +1,4 @@
import { fromUuids, getFeaturesHTMLData } from '../../helpers/utils.mjs'; import { 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,10 +27,6 @@ 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 subclass features for acquisition from the cache // Preload all class 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

@ -37,7 +37,6 @@ 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;

View file

@ -1,5 +1,3 @@
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

@ -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], { first: 'value' }); const { value, type, inline } = parseInlineParams(match[1]);
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,
damageTypes: type type: type
} }
] ]
}; };

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 && !param.includes(':')) { if (first && idx === 0) {
params[first] = param; params[first] = param;
} else { } else {
const parts = param.split(':'); const parts = param.split(':');

View file

@ -879,7 +879,6 @@ 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
); );
@ -896,7 +895,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).filter(id => !!id); const ids = packGroup.map(p => p.parsed.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;

551
package-lock.json generated
View file

@ -13,20 +13,18 @@
"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",
"rollup-plugin-postcss": "^4.0.2", "prettier": "^3.5.3",
"typescript": "^6.0.3", "rollup-plugin-postcss": "^4.0.2"
"typescript-eslint": "^8.60.1"
} }
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
@ -160,27 +158,6 @@
"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",
@ -443,6 +420,19 @@
"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",
@ -771,58 +761,6 @@
"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",
@ -857,288 +795,6 @@
"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",
@ -2197,11 +1853,10 @@
} }
}, },
"node_modules/debug": { "node_modules/debug": {
"version": "4.4.3", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"ms": "^2.1.3" "ms": "^2.1.3"
}, },
@ -2586,6 +2241,37 @@
} }
} }
}, },
"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",
@ -2825,6 +2511,13 @@
"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",
@ -2861,24 +2554,6 @@
"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",
@ -5542,6 +5217,34 @@
"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",
@ -6350,6 +6053,22 @@
"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",
@ -6397,23 +6116,6 @@
"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",
@ -6445,19 +6147,6 @@
"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",
@ -6482,44 +6171,6 @@
"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,20 +24,18 @@
"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",
"rollup-plugin-postcss": "^4.0.2", "prettier": "^3.5.3",
"typescript": "^6.0.3", "rollup-plugin-postcss": "^4.0.2"
"typescript-eslint": "^8.60.1"
}, },
"lint-staged": { "lint-staged": {
"**/*": "eslint --fix" "**/*": "eslint --fix"

View file

@ -1,11 +1,19 @@
@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/utils/index.less'; @import './less//hud/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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,44 @@
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,3 +1,8 @@
@import './sheet.less'; .daggerheart.dialog.dh-style.views.group-roll-dialog {
@import './initialization.less'; .window-content {
@import './main.less'; @import "./_common.less";
}
}
@import "./initialization.less";
@import "./main.less";

View file

@ -1,48 +0,0 @@
.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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +0,0 @@
@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,5 +1,22 @@
@import './activeEffects/index.less'; @import './actions/actions.less';
@import './actions/index.less';
@import './actors/index.less'; @import './actors/actor-sheet-shared.less';
@import './items/index.less';
@import './rollTables/index.less'; @import './actors/adversary/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

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

View file

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

View file

@ -1,10 +0,0 @@
@import './sheet.less';
@import './ability-use.less';
@import './action.less';
@import './chat.less';
@import './damage-summary.less';
@import './deathmoves.less';
@import './downtime.less';
@import './effect-summary.less';
@import './group-roll.less';
@import './refresh-message.less';

View file

@ -1,5 +0,0 @@
@import './combat-sidebar.less';
@import './combatant-controls.less';
@import './encounter-controls.less';
@import './spotlight-control.less';
@import './token-actions.less';

View file

@ -18,7 +18,7 @@
border: 0; border: 0;
box-shadow: none; box-shadow: none;
color: @color-text-primary; color: @color-text-primary;
width: 18.75rem; width: 300px;
pointer-events: all; pointer-events: all;
align-self: flex-end; align-self: flex-end;
transition: 0.3s right ease-in-out; transition: 0.3s right ease-in-out;
@ -36,7 +36,7 @@
transition: opacity var(--ui-fade-duration); transition: opacity var(--ui-fade-duration);
} }
&:not(.performance-low, .noblur) { :not(.performance-low, .noblur) {
backdrop-filter: blur(5px); backdrop-filter: blur(5px);
} }
@ -49,7 +49,8 @@
} }
&.icon-only { &.icon-only {
width: 12rem; width: 180px;
min-width: 180px;
} }
.countdowns-header, .countdowns-header,
@ -107,8 +108,8 @@
gap: 16px; gap: 16px;
img { img {
width: 2.75rem; width: 44px;
height: 2.75rem; height: 44px;
border-radius: 6px; border-radius: 6px;
} }
@ -126,7 +127,7 @@
.countdown-tool-controls { .countdown-tool-controls {
display: flex; display: flex;
align-items: center; align-items: center;
gap: var(--spacer-12); gap: 16px;
} }
.progress-tag { .progress-tag {

View file

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

View file

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

View file

@ -1,11 +1,40 @@
@import './chat/index.less'; @import './chat/ability-use.less';
@import './combat-sidebar/index.less'; @import './chat/action.less';
@import './countdown/index.less'; @import './chat/chat.less';
@import './effects-display/index.less'; @import './chat/damage-summary.less';
@import './item-browser/index.less'; @import './chat/downtime.less';
@import './ownership-selection/index.less'; @import './chat/effect-summary.less';
@import './resources/index.less'; @import './chat/group-roll.less';
@import './scene-config/index.less'; @import './chat/refresh-message.less';
@import './scene-navigation/index.less'; @import './chat/deathmoves.less';
@import './settings/index.less'; @import './chat/sheet.less';
@import './sidebar/index.less';
@import './combat-sidebar/combat-sidebar.less';
@import './combat-sidebar/combatant-controls.less';
@import './combat-sidebar/encounter-controls.less';
@import './combat-sidebar/spotlight-control.less';
@import './combat-sidebar/token-actions.less';
@import './item-browser/item-browser.less';
@import './countdown/countdown.less';
@import './countdown/countdown-edit.less';
@import './countdown/sheet.less';
@import './ownership-selection/ownership-selection.less';
@import './resources/resources.less';
@import './settings/settings.less';
@import './settings/homebrew-settings/domains.less';
@import './settings/homebrew-settings/types.less';
@import './settings/homebrew-settings/resources.less';
@import './settings/appearance-settings/diceSoNice.less';
@import './sidebar/tabs.less';
@import './sidebar/daggerheartMenu.less';
@import './scene-config/scene-config.less';
@import './effects-display/sheet.less';
@import './scene-navigation/scene-navigation.less';

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,3 +0,0 @@
@import './domains.less';
@import './resources.less';
@import './types.less';

View file

@ -1,3 +0,0 @@
@import './settings.less';
@import './appearance-settings/index.less';
@import './homebrew-settings/index.less';

View file

@ -1,2 +0,0 @@
@import './daggerheartMenu.less';
@import './tabs.less';

View file

@ -1,4 +0,0 @@
@import './colors.less';
@import './fonts.less';
@import './mixin.less';
@import './spacing.less';

View file

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

View file

@ -1,2 +1,10 @@
@import './autocomplete/index.less'; @import './tooltip/sheet.less';
@import './tooltip/index.less'; @import './tooltip/tooltip.less';
@import './tooltip/armorManagement.less';
@import './tooltip/battlepoints.less';
@import './tooltip/bordered-tooltip.less';
@import './tooltip/domain-cards.less';
@import './autocomplete/autocomplete.less';
@import './tooltip/resource-management.less';

View file

@ -1,7 +0,0 @@
@import './sheet.less';
@import './armorManagement.less';
@import './battlepoints.less';
@import './bordered-tooltip.less';
@import './domain-cards.less';
@import './resource-management.less';
@import './tooltip.less';

View file

@ -2,7 +2,7 @@
"id": "daggerheart", "id": "daggerheart",
"title": "Daggerheart", "title": "Daggerheart",
"description": "An unofficial implementation of the Daggerheart system", "description": "An unofficial implementation of the Daggerheart system",
"version": "2.3.2", "version": "2.3.1",
"compatibility": { "compatibility": {
"minimum": "14.361", "minimum": "14.361",
"verified": "14.363", "verified": "14.363",
@ -10,7 +10,7 @@
}, },
"url": "https://github.com/Foundryborne/daggerheart", "url": "https://github.com/Foundryborne/daggerheart",
"manifest": "https://raw.githubusercontent.com/Foundryborne/daggerheart/v14/system.json", "manifest": "https://raw.githubusercontent.com/Foundryborne/daggerheart/v14/system.json",
"download": "https://github.com/Foundryborne/daggerheart/releases/download/2.3.2/system.zip", "download": "https://github.com/Foundryborne/daggerheart/releases/download/2.3.1/system.zip",
"authors": [ "authors": [
{ {
"name": "WBHarry" "name": "WBHarry"

View file

@ -11,20 +11,18 @@
</header> </header>
<div class="countdowns-container"> <div class="countdowns-container">
{{#each countdowns as | countdown id |}} {{#each countdowns as | countdown id |}}
<div class="countdown-container {{#if ../iconOnly}}icon-only{{/if}}" data-countdown="{{id}}"> <div class="countdown-container {{#if ../iconOnly}}icon-only{{/if}}">
<div class="countdown-main-container"> <div class="countdown-main-container">
<img src="{{countdown.img}}" {{#if ../iconOnly}}data-tooltip="{{countdown.name}}"{{/if}}/> <img src="{{countdown.img}}" {{#if ../iconOnly}}data-tooltip="{{countdown.name}}"{{/if}}/>
<div class="countdown-content"> <div class="countdown-content">
{{#unless ../iconOnly}} {{#unless ../iconOnly}}<label>{{countdown.name}}</label>{{/unless}}
<header>{{countdown.name}}</header>
{{/unless}}
<div class="countdown-tools"> <div class="countdown-tools">
<div class="countdown-tool-controls"> <div class="countdown-tool-controls">
{{#if countdown.editable}}<a data-action="decreaseCountdown"><i class="fa-solid fa-minus"></i></a>{{/if}} {{#if countdown.editable}}<a data-action="decreaseCountdown" id="{{id}}"><i class="fa-solid fa-minus"></i></a>{{/if}}
<div class="progress-tag"> <div class="progress-tag">
{{countdown.progress.current}}/{{countdown.progress.start}} {{countdown.progress.current}}/{{countdown.progress.start}}
</div> </div>
{{#if countdown.editable}}<a data-action="increaseCountdown"><i class="fa-solid fa-plus"></i></a>{{/if}} {{#if countdown.editable}}<a data-action="increaseCountdown" id="{{id}}"><i class="fa-solid fa-plus"></i></a>{{/if}}
</div> </div>
<div class="countdown-tool-icons"> <div class="countdown-tool-icons">
{{#if (not ../iconOnly)}} {{#if (not ../iconOnly)}}
@ -33,7 +31,7 @@
{{/if}} {{/if}}
{{#unless (eq countdown.progress.looping "noLooping")}} {{#unless (eq countdown.progress.looping "noLooping")}}
<span data-tooltip="{{countdown.loopTooltip}}"> <span data-tooltip="{{countdown.loopTooltip}}">
<a class="looping-container {{#if countdown.shouldLoop}}should-loop{{/if}}" {{#if countdown.loopDisabled}}disabled{{/if}} data-action="loopCountdown"> <a class="looping-container {{#if countdown.shouldLoop}}should-loop{{/if}}" {{#if countdown.loopDisabled}}disabled{{/if}} data-action="loopCountdown" id="{{id}}">
<i class="loop-marker fa-solid fa-repeat"></i> <i class="loop-marker fa-solid fa-repeat"></i>
{{#if (eq countdown.progress.looping "increasing")}} {{#if (eq countdown.progress.looping "increasing")}}
<i class="direction-marker fa-solid fa-angles-up" data-tooltip="{{localize "DAGGERHEART.UI.Countdowns.increasingLoop"}}"></i> <i class="direction-marker fa-solid fa-angles-up" data-tooltip="{{localize "DAGGERHEART.UI.Countdowns.increasingLoop"}}"></i>

View file

@ -82,7 +82,7 @@ function getMean(numbers) {
} }
function getMedianAverageDeviation(numbers, { median }) { function getMedianAverageDeviation(numbers, { median }) {
const residuals = numbers.map(d => Math.abs(d - median)); const residuals = allDamage.map(d => Math.abs(d - median));
return getMedian(residuals); return getMedian(residuals);
} }

View file

@ -2,8 +2,6 @@ import fs from 'fs';
import path from 'path'; import path from 'path';
import readline from 'readline'; import readline from 'readline';
console.log('Creates a foundry symlink in the base folder for type purposes\n');
const askQuestion = question => { const askQuestion = question => {
const rl = readline.createInterface({ const rl = readline.createInterface({
input: process.stdin, input: process.stdin,

View file

@ -1,20 +0,0 @@
import globals from 'globals';
import { defineConfig, globalIgnores } from 'eslint/config';
import { stylisticRules } from '../eslint.config.mjs';
import stylistic from '@stylistic/eslint-plugin';
export default defineConfig([
globalIgnores(['foundry/**/*']),
{
files: ['**/*.{js,mjs,cjs}'],
plugins: {
'@stylistic': stylistic
},
languageOptions: { globals: globals.node },
rules: {
'no-undef': 'error',
'no-unused-vars': 0,
...stylisticRules
}
}
]);