Compare commits

..

3 commits

Author SHA1 Message Date
WBHarry
da44ff2510 Improved optional fieldset styling 2026-06-26 19:31:15 +02:00
WBHarry
1cecb4251d . 2026-06-26 19:23:22 +02:00
WBHarry
e190d1961e . 2026-06-26 19:22:17 +02:00
7 changed files with 81 additions and 4 deletions

View file

@ -381,6 +381,74 @@ Hooks.on(CONFIG.DH.HOOKS.hooksConfig.groupRollStart, async data => {
} }
}); });
const updateActorsRangeDependentEffects = async token => {
if (!token) return;
const rangeMeasurement = game.settings.get(
CONFIG.DH.id,
CONFIG.DH.SETTINGS.gameSettings.variantRules
).rangeMeasurement;
for (let effect of token.actor?.allApplicableEffects() ?? []) {
if (!effect.system.rangeDependence || effect.system.rangeDependence.enabled === false) continue;
const { target, range, type } = effect.system.rangeDependence;
// If there are no targets, assume false. Otherwise, start with the effect enabled.
let enabledEffect = game.user.targets.size !== 0;
// Expect all targets to meet the rangeDependence requirements
for (let userTarget of game.user.targets) {
const disposition = userTarget.document.disposition;
if ((target === 'friendly' && disposition !== 1) || (target === 'hostile' && disposition !== -1)) {
enabledEffect = false;
break;
}
// Get required distance and special case 5 feet to test adjacency
const required = rangeMeasurement[range];
const reverse = type === CONFIG.DH.GENERAL.rangeInclusion.outsideRange.id;
const inRange = userTarget.distanceTo(token.object) <= required;
if (reverse ? inRange : !inRange) {
enabledEffect = false;
break;
}
}
await effect.update({ disabled: !enabledEffect });
}
};
const updateAllRangeDependentEffects = async () => {
const effectsAutomation = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).effects;
if (!effectsAutomation.rangeDependent) return;
const tokens = canvas.scene?.tokens;
if (!tokens) return;
if (game.user.character) {
// The character updates their character's token. There can be only one token.
const characterToken = tokens.find(x => x.actor === game.user.character);
updateActorsRangeDependentEffects(characterToken);
} else if (game.user.isActiveGM) {
// The GM is responsible for all other tokens.
const playerCharacters = game.users.players.filter(x => x.active).map(x => x.character);
for (const token of tokens.filter(x => !playerCharacters.includes(x.actor))) {
updateActorsRangeDependentEffects(token);
}
}
};
const debouncedRangeEffectCall = foundry.utils.debounce(updateAllRangeDependentEffects, 50);
Hooks.on('targetToken', () => {
debouncedRangeEffectCall();
});
Hooks.on('refreshToken', (token, options) => {
if (options.refreshPosition && !token._original) {
debouncedRangeEffectCall();
}
});
Hooks.on('renderCompendiumDirectory', (app, html) => applications.ui.ItemBrowser.injectSidebarButton(html)); Hooks.on('renderCompendiumDirectory', (app, html) => applications.ui.ItemBrowser.injectSidebarButton(html));
Hooks.on('renderDocumentDirectory', (app, html) => applications.ui.ItemBrowser.injectSidebarButton(html)); Hooks.on('renderDocumentDirectory', (app, html) => applications.ui.ItemBrowser.injectSidebarButton(html));

View file

@ -233,6 +233,7 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac
const systemData = { const systemData = {
rangeDependence: event.target.checked rangeDependence: event.target.checked
? { ? {
enabled: true, // Temporary while the onMove handling is still in
type: rangeFields.type.initial, type: rangeFields.type.initial,
target: rangeFields.target.initial, target: rangeFields.target.initial,
range: rangeFields.range.initial range: rangeFields.range.initial

View file

@ -130,7 +130,7 @@ export const otherTargetTypes = {
id: 'any', id: 'any',
label: 'DAGGERHEART.CONFIG.TargetTypes.any' label: 'DAGGERHEART.CONFIG.TargetTypes.any'
} }
} };
export const targetTypes = { export const targetTypes = {
self: { self: {

View file

@ -57,6 +57,10 @@ export default class BaseEffect extends foundry.data.ActiveEffectTypeDataModel {
description: new fields.HTMLField({ label: 'DAGGERHEART.GENERAL.description' }) description: new fields.HTMLField({ label: 'DAGGERHEART.GENERAL.description' })
}), }),
rangeDependence: new fields.SchemaField({ rangeDependence: new fields.SchemaField({
enabled: new fields.BooleanField({ // Temporary for the remaining onMove logic
initial: false,
label: 'DAGGERHEART.GENERAL.enabled'
}),
type: new fields.StringField({ type: new fields.StringField({
required: true, required: true,
choices: CONFIG.DH.GENERAL.rangeInclusion, choices: CONFIG.DH.GENERAL.rangeInclusion,

View file

@ -305,6 +305,10 @@
min-height: auto; min-height: auto;
row-gap: 0; row-gap: 0;
&.active {
row-gap: 10px;
}
legend { legend {
display: flex; display: flex;
align-items: center; align-items: center;

View file

@ -14,7 +14,7 @@
{{/each}} {{/each}}
</ol> </ol>
<fieldset class="armor-change-container optional"> <fieldset class="armor-change-container optional {{#if typeChanges.armor}}active{{/if}}">
<legend> <legend>
{{localize "DAGGERHEART.GENERAL.armor"}} {{localize "DAGGERHEART.GENERAL.armor"}}
<input type="checkbox" class="armor-change-checkbox" data-index="{{typedChanges.armor.index}}" {{checked typedChanges.armor}} /> <input type="checkbox" class="armor-change-checkbox" data-index="{{typedChanges.armor.index}}" {{checked typedChanges.armor}} />

View file

@ -1,5 +1,5 @@
<section class="tab{{#if tab.active}} active{{/if}}" data-group="{{tab.group}}" data-tab="{{tab.id}}"> <section class="tab{{#if tab.active}} active{{/if}}" data-group="{{tab.group}}" data-tab="{{tab.id}}">
<fieldset class="one-column optional"> <fieldset class="one-column optional {{#if source.system.stacking}}active{{/if}}">
<legend> <legend>
{{localize "DAGGERHEART.ACTIVEEFFECT.Config.stacking.title"}} {{localize "DAGGERHEART.ACTIVEEFFECT.Config.stacking.title"}}
<input type="checkbox" class="stacking-change-checkbox" {{checked source.system.stacking}} /> <input type="checkbox" class="stacking-change-checkbox" {{checked source.system.stacking}} />
@ -13,7 +13,7 @@
{{/if}} {{/if}}
</fieldset> </fieldset>
<fieldset class="one-column optional"> <fieldset class="one-column optional {{#if source.system.rangeDependence}}active{{/if}}">
<legend> <legend>
{{localize "DAGGERHEART.ACTIVEEFFECT.Config.rangeDependence.title"}} {{localize "DAGGERHEART.ACTIVEEFFECT.Config.rangeDependence.title"}}
<input type="checkbox" class="range-dependence-change-checkbox" {{checked source.system.rangeDependence}} /> <input type="checkbox" class="range-dependence-change-checkbox" {{checked source.system.rangeDependence}} />