Compare commits

...

3 commits

Author SHA1 Message Date
WBHarry
4dcec2ca61 . 2026-02-25 19:31:45 +01:00
WBHarry
fc7b9a4828 Reworked ActionConfig damage ui 2026-02-25 19:19:36 +01:00
WBHarry
9bda624112 Fixed current actionConfig damage 2026-02-25 18:04:28 +01:00
5 changed files with 104 additions and 50 deletions

View file

@ -1,4 +1,4 @@
import { getNextUnusedDamageType } from '../../helpers/utils.mjs'; import { getUnusedDamageTypes } from '../../helpers/utils.mjs';
import DaggerheartSheet from '../sheets/daggerheart-sheet.mjs'; import DaggerheartSheet from '../sheets/daggerheart-sheet.mjs';
const { ApplicationV2 } = foundry.applications.api; const { ApplicationV2 } = foundry.applications.api;
@ -104,7 +104,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
} }
}; };
static CLEAN_ARRAYS = ['damage.parts', 'cost', 'effects', 'summon']; static CLEAN_ARRAYS = ['cost', 'effects', 'summon'];
_getTabs(tabs) { _getTabs(tabs) {
for (const v of Object.values(tabs)) { for (const v of Object.values(tabs)) {
@ -156,6 +156,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
revealed: this.openTrigger === index revealed: this.openTrigger === index
}; };
}); });
context.allDamageTypesUsed = !getUnusedDamageTypes(this.action.damage.parts).length;
const settingsTiers = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers; const settingsTiers = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers;
context.tierOptions = [ context.tierOptions = [
@ -269,19 +270,61 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
static addDamage(_event) { static addDamage(_event) {
if (!this.action.damage.parts) return; if (!this.action.damage.parts) return;
const data = this.action.toObject();
const type = getNextUnusedDamageType(this.action.damage.parts); const choices = getUnusedDamageTypes(this.action.damage.parts);
const part = { applyTo: type }; const content = new foundry.data.fields.StringField({
if (this.action.actor?.isNPC) part.value = { multiplier: 'flat' }; label: game.i18n.localize('Damage Type'),
data.damage.parts[type] = part; choices,
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); required: true
}).toFormGroup(
{},
{
name: 'type',
localize: true,
nameAttr: 'value',
labelAttr: 'label'
}
).outerHTML;
const callback = (_, button) => {
const data = this.action.toObject();
const type = choices[button.form.elements.type.value].value;
const part = { applyTo: type };
if (this.action.actor?.isNPC) part.value = { multiplier: 'flat' };
data.damage.parts[type] = part;
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
};
const typeDialog = new foundry.applications.api.DialogV2({
buttons: [
foundry.utils.mergeObject(
{
action: 'ok',
label: 'Confirm',
icon: 'fas fa-check',
default: true
},
{ callback: callback }
)
],
content: content,
rejectClose: false,
modal: false,
window: {
title: game.i18n.localize('Add Damage')
},
position: { width: 300 }
});
typeDialog.render(true);
} }
static removeDamage(_event, button) { static removeDamage(_event, button) {
if (!this.action.damage.parts) return; if (!this.action.damage.parts) return;
const data = this.action.toObject(), const data = this.action.toObject();
index = button.dataset.index; const key = button.dataset.key;
data.damage.parts.splice(index, 1); delete data.damage.parts[key];
data.damage.parts[`-=${key}`] = null;
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
} }

View file

@ -287,6 +287,7 @@ export class DHDamageData extends DHResourceData {
return { return {
...super.defineSchema(), ...super.defineSchema(),
base: new fields.BooleanField({ initial: false, readonly: true, label: 'Base' }), base: new fields.BooleanField({ initial: false, readonly: true, label: 'Base' }),
// direct: new fields.BooleanField({ initial: false, label: 'DAGGERHEART.CONFIG.DamageType.direct.name' }),
type: new fields.SetField( type: new fields.SetField(
new fields.StringField({ new fields.StringField({
choices: CONFIG.DH.GENERAL.damageTypes, choices: CONFIG.DH.GENERAL.damageTypes,

View file

@ -558,11 +558,15 @@ export function calculateExpectedValue(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);
} }
export function getNextUnusedDamageType(parts) { export function getUnusedDamageTypes(parts) {
const usedKeys = Object.keys(parts); const usedKeys = Object.keys(parts);
for (const key of Object.keys(CONFIG.DH.GENERAL.healingTypes)) { return Object.keys(CONFIG.DH.GENERAL.healingTypes).reduce((acc, key) => {
if (!usedKeys.includes(key)) return key; if (!usedKeys.includes(key))
} acc.push({
value: key,
label: game.i18n.localize(CONFIG.DH.GENERAL.healingTypes[key].label)
});
return null; return acc;
}, []);
} }

View file

@ -333,6 +333,15 @@
legend { legend {
font-weight: bold; font-weight: bold;
color: light-dark(@dark-blue, @golden); color: light-dark(@dark-blue, @golden);
&.with-icon {
display: flex;
align-items: center;
i {
padding: 0 4px;
}
}
} }
input[type='text'], input[type='text'],

View file

@ -1,12 +1,12 @@
<fieldset class="one-column"> <fieldset class="one-column">
<legend> <legend class="with-icon">
{{#if (eq @root.source.type 'healing')}} {{#if (eq @root.source.type 'healing')}}
{{localize "DAGGERHEART.GENERAL.healing"}} {{localize "DAGGERHEART.GENERAL.healing"}}
{{else}} {{else}}
{{localize "DAGGERHEART.GENERAL.damage"}} {{localize "DAGGERHEART.GENERAL.damage"}}
{{/if}} {{/if}}
{{#unless (eq path 'system.attack.')}}<a><i class="fa-solid fa-plus icon-button" data-action="addDamage"></i></a>{{/unless}} {{#unless (eq path 'system.attack.')}}<a data-action="addDamage" {{#if @root.allDamageTypesUsed}}disabled{{/if}}><i class="fa-solid fa-plus icon-button"></i></a>{{/unless}}
</legend> </legend>
<div class="nest-inputs space-between"> <div class="nest-inputs space-between">
{{#if @root.hasBaseDamage}} {{#if @root.hasBaseDamage}}
@ -16,75 +16,72 @@
{{formField directField value=source.direct name=(concat path "damage.direct") localize=true classes="checkbox"}} {{formField directField value=source.direct name=(concat path "damage.direct") localize=true classes="checkbox"}}
{{/unless}} {{/unless}}
</div> </div>
{{#each source.parts as |dmg index|}} {{#each source.parts as |dmg key|}}
{{#if (and @root.hasBaseDamage @root.source.damage.includeBase)}}
{{setVar 'realIndex' (add index -1)}}
{{else}}
{{setVar 'realIndex' index}}
{{/if}}
<div class="nest-inputs"> <div class="nest-inputs">
<fieldset{{#if dmg.base}} disabled{{/if}} class="one-column{{#if ../path}} no-style{{/if}}"> <fieldset{{#if dmg.base}} disabled{{/if}} class="one-column{{#if ../path}} no-style{{/if}}">
<legend class="with-icon">
{{localize (concat "DAGGERHEART.CONFIG.HealingType." key ".name")}}
{{#unless (or dmg.base ../path)}}
<a data-action="removeDamage" data-key="{{key}}"><i class="fas fa-trash"></i></a>
{{/unless}}
</legend>
{{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base))}} {{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base))}}
{{formField ../fields.resultBased value=dmg.resultBased name=(concat "damage.parts." realIndex ".resultBased") localize=true classes="checkbox"}} {{formField ../fields.resultBased value=dmg.resultBased name=(concat "damage.parts." key ".resultBased") localize=true classes="checkbox"}}
{{/if}} {{/if}}
{{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base) dmg.resultBased)}} {{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base) dmg.resultBased)}}
<div class="nest-inputs"> <div class="nest-inputs">
<fieldset class="one-column"> <fieldset class="one-column">
<legend>{{localize "DAGGERHEART.GENERAL.withThing" thing=(localize "DAGGERHEART.GENERAL.hope")}}</legend> <legend>{{localize "DAGGERHEART.GENERAL.withThing" thing=(localize "DAGGERHEART.GENERAL.hope")}}</legend>
{{> formula fields=../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" realIndex=realIndex path=../path}} {{> formula fields=../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" key=key path=../path}}
</fieldset> </fieldset>
<fieldset class="one-column"> <fieldset class="one-column">
<legend>{{localize "DAGGERHEART.GENERAL.withThing" thing=(localize "DAGGERHEART.GENERAL.fear")}}</legend> <legend>{{localize "DAGGERHEART.GENERAL.withThing" thing=(localize "DAGGERHEART.GENERAL.fear")}}</legend>
{{> formula fields=../fields.valueAlt.fields type=../fields.type dmg=dmg source=dmg.valueAlt target="valueAlt" realIndex=realIndex path=../path}} {{> formula fields=../fields.valueAlt.fields type=../fields.type dmg=dmg source=dmg.valueAlt target="valueAlt" key=key path=../path}}
</fieldset> </fieldset>
</div> </div>
{{else}} {{else}}
<fieldset{{#if dmg.base}} disabled{{/if}} class="one-column"> {{> formula fields=../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" key=key path=../path}}
<legend>{{localize "DAGGERHEART.GENERAL.formula"}}</legend>
{{> formula fields=../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" realIndex=realIndex path=../path}}
</fieldset>
{{/if}} {{/if}}
<div class="nest-inputs">
{{formField ../fields.applyTo value=dmg.applyTo name=(concat ../path "damage.parts." realIndex ".applyTo") localize=true}} {{#if (and (eq dmg.applyTo 'hitPoints') (ne @root.source.type 'healing'))}}
{{#if (and (eq dmg.applyTo 'hitPoints') (ne @root.source.type 'healing'))}} {{formField ../fields.type value=dmg.type name=(concat ../path "damage.parts." key ".type") localize=true}}
{{formField ../fields.type value=dmg.type name=(concat ../path "damage.parts." realIndex ".type") localize=true}} {{/if}}
{{/if}}
</div>
{{#if ../horde}} {{#if ../horde}}
<fieldset class="one-column"> <fieldset class="one-column">
<legend>{{localize "DAGGERHEART.ACTORS.Adversary.hordeDamage"}}</legend> <legend>{{localize "DAGGERHEART.ACTORS.Adversary.hordeDamage"}}</legend>
<div class="nest-inputs"> <div class="nest-inputs">
<input type="hidden" name="{{../path}}damage.parts.{{realIndex}}.valueAlt.multiplier" value="flat"> <input type="hidden" name="{{../path}}damage.parts.{{key}}.valueAlt.multiplier" value="flat">
{{formField ../fields.valueAlt.fields.flatMultiplier value=dmg.valueAlt.flatMultiplier name=(concat ../path "damage.parts." realIndex ".valueAlt.flatMultiplier") label="DAGGERHEART.ACTIONS.Settings.multiplier" classes="inline-child" localize=true }} {{formField ../fields.valueAlt.fields.flatMultiplier value=dmg.valueAlt.flatMultiplier name=(concat ../path "damage.parts." key ".valueAlt.flatMultiplier") label="DAGGERHEART.ACTIONS.Settings.multiplier" classes="inline-child" localize=true }}
{{formField ../fields.valueAlt.fields.dice value=dmg.valueAlt.dice name=(concat ../path "damage.parts." realIndex ".valueAlt.dice") classes="inline-child" localize=true}} {{formField ../fields.valueAlt.fields.dice value=dmg.valueAlt.dice name=(concat ../path "damage.parts." key ".valueAlt.dice") classes="inline-child" localize=true}}
{{formField ../fields.valueAlt.fields.bonus value=dmg.valueAlt.bonus name=(concat ../path "damage.parts." realIndex ".valueAlt.bonus") localize=true classes="inline-child"}} {{formField ../fields.valueAlt.fields.bonus value=dmg.valueAlt.bonus name=(concat ../path "damage.parts." key ".valueAlt.bonus") localize=true classes="inline-child"}}
</div> </div>
</fieldset> </fieldset>
{{/if}} {{/if}}
<input type="hidden" name="damage.parts.{{realIndex}}.base" value="{{dmg.base}}"> <input type="hidden" name="damage.parts.{{key}}.base" value="{{dmg.base}}">
</fieldset> </fieldset>
{{#unless (or dmg.base ../path)}}<div class="fas fa-trash" data-action="removeDamage" data-index="{{realIndex}}"></div>{{/unless}}
</div> </div>
{{/each}} {{/each}}
</fieldset> </fieldset>
{{#*inline "formula"}} {{#*inline "formula"}}
{{#unless dmg.base}} {{#unless dmg.base}}
{{formField fields.custom.fields.enabled value=source.custom.enabled name=(concat path "damage.parts." realIndex "." target ".custom.enabled") classes="checkbox" localize=true}} {{formField fields.custom.fields.enabled value=source.custom.enabled name=(concat path "damage.parts." key "." target ".custom.enabled") classes="checkbox" localize=true}}
{{/unless}} {{/unless}}
{{#if source.custom.enabled}} {{#if source.custom.enabled}}
{{formField fields.custom.fields.formula value=source.custom.formula name=(concat path "damage.parts." realIndex "." target ".custom.formula") localize=true}} {{formField fields.custom.fields.formula value=source.custom.formula name=(concat path "damage.parts." key "." target ".custom.formula") localize=true}}
{{else}} {{else}}
<div class="nest-inputs"> <div class="nest-inputs">
{{#unless @root.isNPC}} {{#unless @root.isNPC}}
{{formField fields.multiplier value=source.multiplier name=(concat path "damage.parts." realIndex "." target ".multiplier") localize=true}} {{formField fields.multiplier value=source.multiplier name=(concat path "damage.parts." key "." target ".multiplier") localize=true}}
{{/unless}} {{/unless}}
{{#if (eq source.multiplier 'flat')}}{{formField fields.flatMultiplier value=source.flatMultiplier name=(concat path "damage.parts." realIndex "." target ".flatMultiplier") localize=true }}{{/if}} {{#if (eq source.multiplier 'flat')}}{{formField fields.flatMultiplier value=source.flatMultiplier name=(concat path "damage.parts." key "." target ".flatMultiplier") localize=true }}{{/if}}
{{formField fields.dice value=source.dice name=(concat path "damage.parts." realIndex "." target ".dice") localize=true}} {{formField fields.dice value=source.dice name=(concat path "damage.parts." key "." target ".dice") localize=true}}
{{formField fields.bonus value=source.bonus name=(concat path "damage.parts." realIndex "." target ".bonus") localize=true}} {{formField fields.bonus value=source.bonus name=(concat path "damage.parts." key "." target ".bonus") localize=true}}
</div> </div>
{{/if}} {{/if}}
{{#if @root.isNPC}} {{#if @root.isNPC}}
<input type="hidden" name="{{path}}damage.parts.{{realIndex}}.{{target}}.multiplier" value="flat"> <input type="hidden" name="{{path}}damage.parts.{{key}}.{{target}}.multiplier" value="flat">
{{/if}} {{/if}}
{{/inline}} {{/inline}}