mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-04-22 23:43:37 +02:00
Fix editing homebrew resources with a custom ResourcesField
This commit is contained in:
parent
f298b2160a
commit
859263e2fd
9 changed files with 109 additions and 83 deletions
|
|
@ -44,8 +44,32 @@ export default class DHBaseActorSettings extends DHApplicationMixin(DocumentShee
|
||||||
const context = await super._prepareContext(options);
|
const context = await super._prepareContext(options);
|
||||||
context.isNPC = this.actor.isNPC;
|
context.isNPC = this.actor.isNPC;
|
||||||
|
|
||||||
if (context.systemFields.attack)
|
if (context.systemFields.attack) {
|
||||||
context.systemFields.attack.fields = this.actor.system.attack.schema.fields;
|
context.systemFields.attack.fields = this.actor.system.attack.schema.fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create fake fields for actor configurable max resource value.
|
||||||
|
const resourceConfig = CONFIG.DH.RESOURCE[this.actor.type]?.all;
|
||||||
|
if (resourceConfig) {
|
||||||
|
const relevant = ['hitPoints', 'stress'].filter(r => r in resourceConfig);
|
||||||
|
context.resources = relevant.map(key => {
|
||||||
|
const data = this.actor._source.system.resources[key];
|
||||||
|
const config = resourceConfig[key];
|
||||||
|
return {
|
||||||
|
label: config.label,
|
||||||
|
name: `system.resources.${key}.max`,
|
||||||
|
value: data.max ?? config.max,
|
||||||
|
tooltip: key === 'hitPoints' ? game.i18n.localize('DAGGERHEART.UI.Tooltip.maxHPClassBound') : null,
|
||||||
|
field: new foundry.data.fields.NumberField({
|
||||||
|
initial: config.max,
|
||||||
|
integer: true,
|
||||||
|
label: game.i18n.format('DAGGERHEART.GENERAL.maxWithThing', {
|
||||||
|
thing: game.i18n.localize(config.label)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ const characterBaseResources = Object.freeze({
|
||||||
hope: {
|
hope: {
|
||||||
id: 'hope',
|
id: 'hope',
|
||||||
initial: 2,
|
initial: 2,
|
||||||
min: 0,
|
|
||||||
reverse: false,
|
reverse: false,
|
||||||
label: 'DAGGERHEART.GENERAL.hope'
|
label: 'DAGGERHEART.GENERAL.hope'
|
||||||
}
|
}
|
||||||
|
|
@ -65,7 +64,6 @@ const companionBaseResources = Object.freeze({
|
||||||
hope: {
|
hope: {
|
||||||
id: 'hope',
|
id: 'hope',
|
||||||
initial: 0,
|
initial: 0,
|
||||||
min: 0,
|
|
||||||
reverse: false,
|
reverse: false,
|
||||||
label: 'DAGGERHEART.GENERAL.hope'
|
label: 'DAGGERHEART.GENERAL.hope'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -587,6 +587,7 @@ export default class DhCharacter extends DhCreature {
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareBaseData() {
|
prepareBaseData() {
|
||||||
|
super.prepareBaseData();
|
||||||
this.evasion += this.class.value?.system?.evasion ?? 0;
|
this.evasion += this.class.value?.system?.evasion ?? 0;
|
||||||
|
|
||||||
const currentLevel = this.levelData.level.current;
|
const currentLevel = this.levelData.level.current;
|
||||||
|
|
|
||||||
|
|
@ -123,6 +123,7 @@ export default class DhCompanion extends DhCreature {
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareBaseData() {
|
prepareBaseData() {
|
||||||
|
super.prepareBaseData();
|
||||||
this.attack.roll.bonus = this.partner?.system?.spellcastModifier ?? 0;
|
this.attack.roll.bonus = this.partner?.system?.spellcastModifier ?? 0;
|
||||||
|
|
||||||
for (let levelKey in this.levelData.levelups) {
|
for (let levelKey in this.levelData.levelups) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { resourceField } from '../fields/actorField.mjs';
|
import { ResourcesField } from '../fields/actorField.mjs';
|
||||||
import BaseDataActor from './base.mjs';
|
import BaseDataActor from './base.mjs';
|
||||||
|
|
||||||
export default class DhCreature extends BaseDataActor {
|
export default class DhCreature extends BaseDataActor {
|
||||||
|
|
@ -8,36 +8,7 @@ export default class DhCreature extends BaseDataActor {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...super.defineSchema(),
|
...super.defineSchema(),
|
||||||
resources: new fields.SchemaField({
|
resources: new ResourcesField(this.metadata.type),
|
||||||
...Object.values(CONFIG.DH.RESOURCE[this.metadata.type].all).reduce(
|
|
||||||
(acc, resource) => {
|
|
||||||
if (resource.max !== undefined) {
|
|
||||||
acc[resource.id] = resourceField(
|
|
||||||
resource.max,
|
|
||||||
resource.initial,
|
|
||||||
resource.label,
|
|
||||||
resource.maxLabel
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
acc[resource.id] = new fields.SchemaField(
|
|
||||||
{
|
|
||||||
value: new fields.NumberField({
|
|
||||||
initial: resource.initial,
|
|
||||||
min: resource.min,
|
|
||||||
integer: true,
|
|
||||||
label: resource.label
|
|
||||||
}),
|
|
||||||
isReversed: new fields.BooleanField({ initial: resource.reverse })
|
|
||||||
},
|
|
||||||
{ label: resource.label }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
{}
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
advantageSources: new fields.ArrayField(new fields.StringField(), {
|
advantageSources: new fields.ArrayField(new fields.StringField(), {
|
||||||
label: 'DAGGERHEART.ACTORS.Character.advantageSources.label',
|
label: 'DAGGERHEART.ACTORS.Character.advantageSources.label',
|
||||||
hint: 'DAGGERHEART.ACTORS.Character.advantageSources.hint'
|
hint: 'DAGGERHEART.ACTORS.Character.advantageSources.hint'
|
||||||
|
|
@ -56,17 +27,6 @@ export default class DhCreature extends BaseDataActor {
|
||||||
return !vulnerableAppliedByOther;
|
return !vulnerableAppliedByOther;
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareDerivedData() {
|
|
||||||
super.prepareDerivedData();
|
|
||||||
const resources = CONFIG.DH.RESOURCE[this.metadata.type].all;
|
|
||||||
if (resources) {
|
|
||||||
for (const [key, value] of Object.entries(this.resources)) {
|
|
||||||
value.label = resources[key]?.label;
|
|
||||||
value.isReversed = resources[key]?.reverse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async _preUpdate(changes, options, userId) {
|
async _preUpdate(changes, options, userId) {
|
||||||
const allowed = await super._preUpdate(changes, options, userId);
|
const allowed = await super._preUpdate(changes, options, userId);
|
||||||
if (allowed === false) return;
|
if (allowed === false) return;
|
||||||
|
|
|
||||||
|
|
@ -6,21 +6,6 @@ const attributeField = label =>
|
||||||
tierMarked: new fields.BooleanField({ initial: false })
|
tierMarked: new fields.BooleanField({ initial: false })
|
||||||
});
|
});
|
||||||
|
|
||||||
const resourceField = (max = 0, initial = 0, label, maxLabel) =>
|
|
||||||
new fields.SchemaField(
|
|
||||||
{
|
|
||||||
value: new fields.NumberField({ initial: initial, min: 0, integer: true, label }),
|
|
||||||
max: new fields.NumberField({
|
|
||||||
initial: max,
|
|
||||||
integer: true,
|
|
||||||
label:
|
|
||||||
maxLabel ??
|
|
||||||
game.i18n.format('DAGGERHEART.GENERAL.maxWithThing', { thing: game.i18n.localize(label) })
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{ label }
|
|
||||||
);
|
|
||||||
|
|
||||||
const stressDamageReductionRule = localizationPath =>
|
const stressDamageReductionRule = localizationPath =>
|
||||||
new fields.SchemaField({
|
new fields.SchemaField({
|
||||||
cost: new fields.NumberField({
|
cost: new fields.NumberField({
|
||||||
|
|
@ -36,4 +21,67 @@ const bonusField = label =>
|
||||||
dice: new fields.ArrayField(new fields.StringField(), { label: `${game.i18n.localize(label)} Dice` })
|
dice: new fields.ArrayField(new fields.StringField(), { label: `${game.i18n.localize(label)} Dice` })
|
||||||
});
|
});
|
||||||
|
|
||||||
export { attributeField, resourceField, stressDamageReductionRule, bonusField };
|
/**
|
||||||
|
* Field used for actor resources. It is a resource that validates dynamically based on the config.
|
||||||
|
* Because "max" may be defined during runtime, we don't attempt to clamp the maximum value.
|
||||||
|
*/
|
||||||
|
class ResourcesField extends fields.TypedObjectField {
|
||||||
|
constructor(actorType) {
|
||||||
|
super(
|
||||||
|
new fields.SchemaField({
|
||||||
|
value: new fields.NumberField({ min: 0, initial: 0, integer: true }),
|
||||||
|
// Some resources allow changing max. A null max means its the default
|
||||||
|
max: new fields.NumberField({ initial: null, integer: true, nullable: true })
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.actorType = actorType;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInitialValue() {
|
||||||
|
const resources = CONFIG.DH.RESOURCE[this.actorType].all;
|
||||||
|
return Object.values(resources).reduce((result, resource) => {
|
||||||
|
result[resource.id] = {
|
||||||
|
value: resource.initial,
|
||||||
|
max: null
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
_validateKey(key) {
|
||||||
|
return key in CONFIG.DH.RESOURCE[this.actorType].all;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanType(value, options) {
|
||||||
|
value = super._cleanType(value, options);
|
||||||
|
|
||||||
|
// If not partial, ensure all data exists
|
||||||
|
if (!options.partial) {
|
||||||
|
value = foundry.utils.mergeObject(this.getInitialValue(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Initializes the original source data, returning prepared data */
|
||||||
|
initialize(...args) {
|
||||||
|
const data = super.initialize(...args);
|
||||||
|
const resources = CONFIG.DH.RESOURCE[this.actorType].all;
|
||||||
|
for (const [key, value] of Object.entries(data)) {
|
||||||
|
// TypedObjectField only calls _validateKey when persisting, so we also call it here
|
||||||
|
if (!this._validateKey(key)) {
|
||||||
|
delete value[key];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add basic prepared data.
|
||||||
|
const resource = resources[key];
|
||||||
|
value.label = resource.label;
|
||||||
|
value.isReversed = resources[key].reverse;
|
||||||
|
value.max = typeof resource.max === 'number' ? value.max ?? resource.max : null;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { attributeField, ResourcesField, stressDamageReductionRule, bonusField };
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,10 @@
|
||||||
|
|
||||||
<div class="fieldsets-section">
|
<div class="fieldsets-section">
|
||||||
<fieldset class="flex">
|
<fieldset class="flex">
|
||||||
<legend>{{localize "DAGGERHEART.GENERAL.HitPoints.plural"}}</legend>
|
<legend>{{localize "DAGGERHEART.GENERAL.Resource.plural"}}</legend>
|
||||||
{{formGroup systemFields.resources.fields.hitPoints.fields.value value=document._source.system.resources.hitPoints.value label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.resources.hitPoints.value.label")}}
|
{{#each resources as |resource|}}
|
||||||
{{formGroup systemFields.resources.fields.hitPoints.fields.max value=document._source.system.resources.hitPoints.max label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.resources.hitPoints.max.label")}}
|
{{formGroup resource.field value=resource.value name=resource.name}}
|
||||||
</fieldset>
|
{{/each}}
|
||||||
<fieldset class="flex">
|
|
||||||
<legend>{{localize "DAGGERHEART.GENERAL.stress"}}</legend>
|
|
||||||
{{formGroup systemFields.resources.fields.stress.fields.value value=document._source.system.resources.stress.value label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.resources.stress.value.label")}}
|
|
||||||
{{formGroup systemFields.resources.fields.stress.fields.max value=document._source.system.resources.stress.max label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.resources.stress.max.label")}}
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,15 +22,12 @@
|
||||||
<legend>{{localize 'DAGGERHEART.GENERAL.basics'}}</legend>
|
<legend>{{localize 'DAGGERHEART.GENERAL.basics'}}</legend>
|
||||||
|
|
||||||
<div class="two-columns even">
|
<div class="two-columns even">
|
||||||
{{formGroup systemFields.resources.fields.hitPoints.fields.value value=document._source.system.resources.hitPoints.value localize=true}}
|
{{#each resources as |resource|}}
|
||||||
<span data-tooltip-text="{{localize "DAGGERHEART.UI.Tooltip.maxHPClassBound"}}">
|
<span {{#if resource.tooltip}}data-tooltip-text="{{resource.tooltip}}"{{/if}}>
|
||||||
{{formGroup systemFields.resources.fields.hitPoints.fields.max value=document._source.system.resources.hitPoints.max localize=true}}
|
{{formGroup resource.field value=resource.value name=resource.name}}
|
||||||
</span>
|
</span>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
{{formGroup systemFields.resources.fields.stress.fields.value value=document._source.system.resources.stress.value localize=true}}
|
|
||||||
{{formGroup systemFields.resources.fields.stress.fields.max value=document._source.system.resources.stress.max localize=true}}
|
|
||||||
|
|
||||||
{{formGroup systemFields.resources.fields.hope.fields.value value=document._source.system.resources.hope.value localize=true}}
|
|
||||||
{{formGroup systemFields.scars value=document._source.system.scars localize=true}}
|
{{formGroup systemFields.scars value=document._source.system.scars localize=true}}
|
||||||
|
|
||||||
{{formGroup systemFields.proficiency value=document._source.system.proficiency localize=true}}
|
{{formGroup systemFields.proficiency value=document._source.system.proficiency localize=true}}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,9 @@
|
||||||
<legend>{{localize 'DAGGERHEART.GENERAL.basics'}}</legend>
|
<legend>{{localize 'DAGGERHEART.GENERAL.basics'}}</legend>
|
||||||
<div class="nest-inputs">
|
<div class="nest-inputs">
|
||||||
{{formGroup systemFields.evasion value=document._source.system.evasion localize=true}}
|
{{formGroup systemFields.evasion value=document._source.system.evasion localize=true}}
|
||||||
{{formGroup systemFields.resources.fields.stress.fields.value value=document._source.system.resources.stress.value label='DAGGERHEART.ACTORS.Companion.FIELDS.resources.stress.currentStress.label' localize=true}}
|
{{#each resources as |resource|}}
|
||||||
{{formGroup systemFields.resources.fields.stress.fields.max value=document._source.system.resources.stress.max label='DAGGERHEART.ACTORS.Companion.FIELDS.resources.stress.maxStress.label' localize=true}}
|
{{formGroup resource.field value=resource.value name=resource.name}}
|
||||||
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="form-fields">
|
<div class="form-fields">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue