mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-03-07 14:36:13 +01:00
Initial v14 fixes
This commit is contained in:
parent
b374070809
commit
1a928e950c
19 changed files with 197 additions and 180 deletions
|
|
@ -33,6 +33,7 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac
|
||||||
settings: { template: 'systems/daggerheart/templates/sheets/activeEffect/settings.hbs' },
|
settings: { template: 'systems/daggerheart/templates/sheets/activeEffect/settings.hbs' },
|
||||||
changes: {
|
changes: {
|
||||||
template: 'systems/daggerheart/templates/sheets/activeEffect/changes.hbs',
|
template: 'systems/daggerheart/templates/sheets/activeEffect/changes.hbs',
|
||||||
|
templates: ['systems/daggerheart/templates/sheets/activeEffect/change.hbs'],
|
||||||
scrollable: ['ol[data-changes]']
|
scrollable: ['ol[data-changes]']
|
||||||
},
|
},
|
||||||
footer: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-form-footer.hbs' }
|
footer: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-form-footer.hbs' }
|
||||||
|
|
@ -121,8 +122,41 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'changes':
|
||||||
|
const fields = this.document.system.schema.fields.changes.element.fields;
|
||||||
|
partContext.changes = await Promise.all(
|
||||||
|
foundry.utils
|
||||||
|
.deepClone(context.source.changes)
|
||||||
|
.map((c, i) => this._prepareChangeContext(c, i, fields))
|
||||||
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return partContext;
|
return partContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_prepareChangeContext(change, index, fields) {
|
||||||
|
if (typeof change.value !== 'string') change.value = JSON.stringify(change.value);
|
||||||
|
const defaultPriority = game.system.api.documents.DhActiveEffect.CHANGE_TYPES[change.type]?.defaultPriority;
|
||||||
|
Object.assign(
|
||||||
|
change,
|
||||||
|
['key', 'type', 'value', 'priority'].reduce((paths, fieldName) => {
|
||||||
|
paths[`${fieldName}Path`] = `system.changes.${index}.${fieldName}`;
|
||||||
|
return paths;
|
||||||
|
}, {})
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
game.system.api.documents.DhActiveEffect.CHANGE_TYPES[change.type].render?.(
|
||||||
|
change,
|
||||||
|
index,
|
||||||
|
defaultPriority
|
||||||
|
) ??
|
||||||
|
renderTemplate('systems/daggerheart/templates/sheets/activeEffect/change.hbs', {
|
||||||
|
change,
|
||||||
|
index,
|
||||||
|
defaultPriority,
|
||||||
|
fields
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,18 +72,6 @@ const typeSettingsMap = {
|
||||||
*/
|
*/
|
||||||
export default function DHApplicationMixin(Base) {
|
export default function DHApplicationMixin(Base) {
|
||||||
class DHSheetV2 extends HandlebarsApplicationMixin(Base) {
|
class DHSheetV2 extends HandlebarsApplicationMixin(Base) {
|
||||||
/**
|
|
||||||
* @param {DHSheetV2Configuration} [options={}]
|
|
||||||
*/
|
|
||||||
constructor(options = {}) {
|
|
||||||
super(options);
|
|
||||||
/**
|
|
||||||
* @type {foundry.applications.ux.DragDrop[]}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this._dragDrop = this._createDragDropHandlers();
|
|
||||||
}
|
|
||||||
|
|
||||||
#nonHeaderAttribution = ['environment', 'ancestry', 'community', 'domainCard'];
|
#nonHeaderAttribution = ['environment', 'ancestry', 'community', 'domainCard'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -177,7 +165,7 @@ export default function DHApplicationMixin(Base) {
|
||||||
/**@inheritdoc */
|
/**@inheritdoc */
|
||||||
_attachPartListeners(partId, htmlElement, options) {
|
_attachPartListeners(partId, htmlElement, options) {
|
||||||
super._attachPartListeners(partId, htmlElement, options);
|
super._attachPartListeners(partId, htmlElement, options);
|
||||||
this._dragDrop.forEach(d => d.bind(htmlElement));
|
// this._dragDrop.forEach(d => d.bind(htmlElement));
|
||||||
|
|
||||||
// Handle delta inputs
|
// Handle delta inputs
|
||||||
for (const deltaInput of htmlElement.querySelectorAll('input[data-allow-delta]')) {
|
for (const deltaInput of htmlElement.querySelectorAll('input[data-allow-delta]')) {
|
||||||
|
|
@ -350,21 +338,6 @@ export default function DHApplicationMixin(Base) {
|
||||||
/* Drag and Drop */
|
/* Drag and Drop */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates drag-drop handlers from the configured options.
|
|
||||||
* @returns {foundry.applications.ux.DragDrop[]}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_createDragDropHandlers() {
|
|
||||||
return this.options.dragDrop.map(d => {
|
|
||||||
d.callbacks = {
|
|
||||||
dragstart: this._onDragStart.bind(this),
|
|
||||||
drop: this._onDrop.bind(this)
|
|
||||||
};
|
|
||||||
return new foundry.applications.ux.DragDrop.implementation(d);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle dragStart event.
|
* Handle dragStart event.
|
||||||
* @param {DragEvent} event
|
* @param {DragEvent} event
|
||||||
|
|
|
||||||
|
|
@ -52,10 +52,6 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
get element() {
|
|
||||||
return document.body.querySelector('.daggerheart.dh-style.countdowns');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**@inheritdoc */
|
/**@inheritdoc */
|
||||||
async _renderFrame(options) {
|
async _renderFrame(options) {
|
||||||
const frame = await super._renderFrame(options);
|
const frame = await super._renderFrame(options);
|
||||||
|
|
@ -68,6 +64,7 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
|
||||||
|
|
||||||
const header = frame.querySelector('.window-header');
|
const header = frame.querySelector('.window-header');
|
||||||
header.querySelector('button[data-action="close"]').remove();
|
header.querySelector('button[data-action="close"]').remove();
|
||||||
|
header.querySelector('button[data-action="toggleControls"]').remove();
|
||||||
|
|
||||||
if (game.user.isGM) {
|
if (game.user.isGM) {
|
||||||
const editTooltip = game.i18n.localize('DAGGERHEART.APPLICATIONS.CountdownEdit.editTitle');
|
const editTooltip = game.i18n.localize('DAGGERHEART.APPLICATIONS.CountdownEdit.editTitle');
|
||||||
|
|
@ -278,9 +275,7 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
|
||||||
return acc;
|
return acc;
|
||||||
}, {})
|
}, {})
|
||||||
};
|
};
|
||||||
await emitAsGM(GMUpdateEvent.UpdateCountdowns,
|
await emitAsGM(GMUpdateEvent.UpdateCountdowns, DhCountdowns.gmSetSetting.bind(settings), settings, null, {
|
||||||
DhCountdowns.gmSetSetting.bind(settings),
|
|
||||||
settings, null, {
|
|
||||||
refreshType: RefreshType.Countdown
|
refreshType: RefreshType.Countdown
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ export default class DhTemplateLayer extends foundry.canvas.layers.TemplateLayer
|
||||||
order: 2,
|
order: 2,
|
||||||
title: 'CONTROLS.GroupMeasure',
|
title: 'CONTROLS.GroupMeasure',
|
||||||
icon: 'fa-solid fa-ruler-combined',
|
icon: 'fa-solid fa-ruler-combined',
|
||||||
visible: game.user.can('TEMPLATE_CREATE'),
|
visible: game.user.can('REGION_CREATE'),
|
||||||
onChange: (event, active) => {
|
onChange: (event, active) => {
|
||||||
if (active) canvas.templates.activate();
|
if (active) canvas.templates.activate();
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,12 @@ export const range = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* circle|cone|rect|ray used to be CONST.MEASURED_TEMPLATE_TYPES. Hardcoded for now */
|
||||||
export const templateTypes = {
|
export const templateTypes = {
|
||||||
...CONST.MEASURED_TEMPLATE_TYPES,
|
CIRCLE: 'circle',
|
||||||
|
CONE: 'cone',
|
||||||
|
RECTANGLE: 'rect',
|
||||||
|
RAY: 'ray',
|
||||||
EMANATION: 'emanation',
|
EMANATION: 'emanation',
|
||||||
INFRONT: 'inFront'
|
INFRONT: 'inFront'
|
||||||
};
|
};
|
||||||
|
|
@ -737,3 +741,36 @@ export const sceneRangeMeasurementSetting = {
|
||||||
label: 'Custom'
|
label: 'Custom'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const activeEffectModes = {
|
||||||
|
custom: {
|
||||||
|
id: 'custom',
|
||||||
|
priority: 0,
|
||||||
|
label: 'EFFECT.CHANGES.TYPES.custom'
|
||||||
|
},
|
||||||
|
multiply: {
|
||||||
|
id: 'multiply',
|
||||||
|
priority: 10,
|
||||||
|
label: 'EFFECT.CHANGES.TYPES.multiply'
|
||||||
|
},
|
||||||
|
add: {
|
||||||
|
id: 'add',
|
||||||
|
priority: 20,
|
||||||
|
label: 'EFFECT.CHANGES.TYPES.add'
|
||||||
|
},
|
||||||
|
downgrade: {
|
||||||
|
id: 'downgrade',
|
||||||
|
priority: 30,
|
||||||
|
label: 'EFFECT.CHANGES.TYPES.downgrade'
|
||||||
|
},
|
||||||
|
upgrade: {
|
||||||
|
id: 'upgrade',
|
||||||
|
priority: 40,
|
||||||
|
label: 'EFFECT.CHANGES.TYPES.upgrade'
|
||||||
|
},
|
||||||
|
override: {
|
||||||
|
id: 'override',
|
||||||
|
priority: 50,
|
||||||
|
label: 'EFFECT.CHANGES.TYPES.override'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,84 +2,4 @@ import DHBaseAction from './baseAction.mjs';
|
||||||
|
|
||||||
export default class DhBeastformAction extends DHBaseAction {
|
export default class DhBeastformAction extends DHBaseAction {
|
||||||
static extraSchemas = [...super.extraSchemas, 'beastform'];
|
static extraSchemas = [...super.extraSchemas, 'beastform'];
|
||||||
|
|
||||||
/* async use(event, options) {
|
|
||||||
const beastformConfig = this.prepareBeastformConfig();
|
|
||||||
|
|
||||||
const abort = await this.handleActiveTransformations();
|
|
||||||
if (abort) return;
|
|
||||||
|
|
||||||
const calcCosts = game.system.api.fields.ActionFields.CostField.calcCosts.call(this, this.cost);
|
|
||||||
const hasCost = game.system.api.fields.ActionFields.CostField.hasCost.call(this, calcCosts);
|
|
||||||
if (!hasCost) {
|
|
||||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.insufficientResources'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { selected, evolved, hybrid } = await BeastformDialog.configure(beastformConfig, this.item);
|
|
||||||
if (!selected) return;
|
|
||||||
|
|
||||||
const result = await super.use(event, options);
|
|
||||||
if (!result) return;
|
|
||||||
|
|
||||||
await this.transform(selected, evolved, hybrid);
|
|
||||||
}
|
|
||||||
|
|
||||||
prepareBeastformConfig(config) {
|
|
||||||
const settingsTiers = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers;
|
|
||||||
const actorLevel = this.actor.system.levelData.level.current;
|
|
||||||
const actorTier =
|
|
||||||
Object.values(settingsTiers).find(
|
|
||||||
tier => actorLevel >= tier.levels.start && actorLevel <= tier.levels.end
|
|
||||||
) ?? 1;
|
|
||||||
|
|
||||||
return {
|
|
||||||
tierLimit: this.beastform.tierAccess.exact ?? actorTier
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async transform(selectedForm, evolvedData, hybridData) {
|
|
||||||
const formData = evolvedData?.form ? evolvedData.form.toObject() : selectedForm.toObject();
|
|
||||||
const beastformEffect = formData.effects.find(x => x.type === 'beastform');
|
|
||||||
if (!beastformEffect) {
|
|
||||||
ui.notifications.error('DAGGERHEART.UI.Notifications.beastformMissingEffect');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (evolvedData?.form) {
|
|
||||||
const evolvedForm = selectedForm.effects.find(x => x.type === 'beastform');
|
|
||||||
if (!evolvedForm) {
|
|
||||||
ui.notifications.error('DAGGERHEART.UI.Notifications.beastformMissingEffect');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
beastformEffect.changes = [...beastformEffect.changes, ...evolvedForm.changes];
|
|
||||||
formData.system.features = [...formData.system.features, ...selectedForm.system.features.map(x => x.uuid)];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedForm.system.beastformType === CONFIG.DH.ITEM.beastformTypes.hybrid.id) {
|
|
||||||
formData.system.advantageOn = Object.values(hybridData.advantages).reduce((advantages, formCategory) => {
|
|
||||||
Object.keys(formCategory).forEach(advantageKey => {
|
|
||||||
advantages[advantageKey] = formCategory[advantageKey];
|
|
||||||
});
|
|
||||||
return advantages;
|
|
||||||
}, {});
|
|
||||||
formData.system.features = [
|
|
||||||
...formData.system.features,
|
|
||||||
...Object.values(hybridData.features).flatMap(x => Object.keys(x))
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.actor.createEmbeddedDocuments('Item', [formData]);
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleActiveTransformations() {
|
|
||||||
const beastformEffects = this.actor.effects.filter(x => x.type === 'beastform');
|
|
||||||
const existingEffects = beastformEffects.length > 0;
|
|
||||||
await this.actor.deleteEmbeddedDocuments(
|
|
||||||
'ActiveEffect',
|
|
||||||
beastformEffects.map(x => x.id)
|
|
||||||
);
|
|
||||||
return existingEffects;
|
|
||||||
} */
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,27 @@
|
||||||
* "Anything that uses another data model value as its value": +1 - Effects that increase traits have to be calculated first at Base priority. (EX: Raise evasion by half your agility)
|
* "Anything that uses another data model value as its value": +1 - Effects that increase traits have to be calculated first at Base priority. (EX: Raise evasion by half your agility)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default class BaseEffect extends foundry.abstract.TypeDataModel {
|
export default class BaseEffect extends foundry.data.ActiveEffectTypeDataModel {
|
||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
...super.defineSchema(),
|
||||||
|
changes: new fields.ArrayField(
|
||||||
|
new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ required: true }),
|
||||||
|
type: new fields.StringField({
|
||||||
|
required: true,
|
||||||
|
blank: false,
|
||||||
|
choices: CONFIG.DH.GENERAL.activeEffectModes,
|
||||||
|
initial: CONFIG.DH.GENERAL.activeEffectModes.add.id,
|
||||||
|
validate: BaseEffect.#validateType
|
||||||
|
}),
|
||||||
|
value: new fields.AnyField({ required: true, nullable: true, serializable: true, initial: '' }),
|
||||||
|
phase: new fields.StringField({ required: true, blank: false, initial: 'initial' }),
|
||||||
|
priority: new fields.NumberField()
|
||||||
|
})
|
||||||
|
),
|
||||||
rangeDependence: new fields.SchemaField({
|
rangeDependence: new fields.SchemaField({
|
||||||
enabled: new fields.BooleanField({
|
enabled: new fields.BooleanField({
|
||||||
required: true,
|
required: true,
|
||||||
|
|
@ -45,6 +61,23 @@ export default class BaseEffect extends foundry.abstract.TypeDataModel {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate that an {@link EffectChangeData#type} string is well-formed.
|
||||||
|
* @param {string} type The string to be validated
|
||||||
|
* @returns {true}
|
||||||
|
* @throws {Error} An error if the type string is malformed
|
||||||
|
*/
|
||||||
|
static #validateType(type) {
|
||||||
|
if (type.length < 3) throw new Error('must be at least three characters long');
|
||||||
|
if (!/^custom\.-?\d+$/.test(type) && !type.split('.').every(s => /^[a-z0-9]+$/i.test(s))) {
|
||||||
|
throw new Error(
|
||||||
|
'A change type must either be a sequence of dot-delimited, alpha-numeric substrings or of the form' +
|
||||||
|
' "custom.{number}"'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static getDefaultObject() {
|
static getDefaultObject() {
|
||||||
return {
|
return {
|
||||||
name: 'New Effect',
|
name: 'New Effect',
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ export default class BeastformEffect extends BaseEffect {
|
||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
return {
|
return {
|
||||||
|
...super.defineSchema(),
|
||||||
characterTokenData: new fields.SchemaField({
|
characterTokenData: new fields.SchemaField({
|
||||||
usesDynamicToken: new fields.BooleanField({ initial: false }),
|
usesDynamicToken: new fields.BooleanField({ initial: false }),
|
||||||
tokenImg: new fields.FilePathField({
|
tokenImg: new fields.FilePathField({
|
||||||
|
|
|
||||||
|
|
@ -111,9 +111,17 @@ export class ActionField extends foundry.data.fields.ObjectField {
|
||||||
* @param {object} sourceData Candidate source data of the root model.
|
* @param {object} sourceData Candidate source data of the root model.
|
||||||
* @param {any} fieldData The value of this field within the source data.
|
* @param {any} fieldData The value of this field within the source data.
|
||||||
*/
|
*/
|
||||||
migrateSource(sourceData, fieldData) {
|
_migrate(sourceData, _fieldData) {
|
||||||
const cls = this.getModel(fieldData);
|
const source = sourceData ?? this.options.initial;
|
||||||
if (cls) cls.migrateDataSafe(fieldData);
|
if (!source) return sourceData;
|
||||||
|
|
||||||
|
const cls = this.getModel(source);
|
||||||
|
if (cls) {
|
||||||
|
cls.migrateDataSafe(source);
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,12 +101,13 @@ export default class DHBeastform extends BaseDataItem {
|
||||||
const effect = this.parent.effects.find(x => x.type === 'beastform');
|
const effect = this.parent.effects.find(x => x.type === 'beastform');
|
||||||
if (!effect) return null;
|
if (!effect) return null;
|
||||||
|
|
||||||
const traitBonus = effect.changes.find(x => x.key === `system.traits.${this.mainTrait}.value`)?.value ?? 0;
|
const traitBonus =
|
||||||
const evasionBonus = effect.changes.find(x => x.key === 'system.evasion')?.value ?? 0;
|
effect.system.changes.find(x => x.key === `system.traits.${this.mainTrait}.value`)?.value ?? 0;
|
||||||
|
const evasionBonus = effect.system.changes.find(x => x.key === 'system.evasion')?.value ?? 0;
|
||||||
|
|
||||||
const damageDiceIndex = effect.changes.find(x => x.key === 'system.rules.attack.damage.diceIndex');
|
const damageDiceIndex = effect.system.changes.find(x => x.key === 'system.rules.attack.damage.diceIndex');
|
||||||
const damageDice = damageDiceIndex ? Object.keys(CONFIG.DH.GENERAL.diceTypes)[damageDiceIndex.value] : null;
|
const damageDice = damageDiceIndex ? Object.keys(CONFIG.DH.GENERAL.diceTypes)[damageDiceIndex.value] : null;
|
||||||
const damageBonus = effect.changes.find(x => x.key === 'system.rules.attack.damage.bonus')?.value ?? 0;
|
const damageBonus = effect.system.changes.find(x => x.key === 'system.rules.attack.damage.bonus')?.value ?? 0;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
trait: game.i18n.localize(CONFIG.DH.ACTOR.abilities[this.mainTrait].label),
|
trait: game.i18n.localize(CONFIG.DH.ACTOR.abilities[this.mainTrait].label),
|
||||||
|
|
@ -169,8 +170,9 @@ export default class DHBeastform extends BaseDataItem {
|
||||||
|
|
||||||
const beastformEffect = this.parent.effects.find(x => x.type === 'beastform');
|
const beastformEffect = this.parent.effects.find(x => x.type === 'beastform');
|
||||||
await beastformEffect.updateSource({
|
await beastformEffect.updateSource({
|
||||||
|
system: {
|
||||||
changes: [
|
changes: [
|
||||||
...beastformEffect.changes,
|
...beastformEffect.system.changes,
|
||||||
{
|
{
|
||||||
key: 'system.advantageSources',
|
key: 'system.advantageSources',
|
||||||
mode: 2,
|
mode: 2,
|
||||||
|
|
@ -179,7 +181,6 @@ export default class DHBeastform extends BaseDataItem {
|
||||||
.join(', ')
|
.join(', ')
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
system: {
|
|
||||||
characterTokenData: {
|
characterTokenData: {
|
||||||
usesDynamicToken: this.parent.parent.prototypeToken.ring.enabled,
|
usesDynamicToken: this.parent.parent.prototypeToken.ring.enabled,
|
||||||
tokenImg: this.parent.parent.prototypeToken.texture.src,
|
tokenImg: this.parent.parent.prototypeToken.texture.src,
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,9 @@ export default class DHSubclass extends BaseDataItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
async _preCreate(data, options, user) {
|
async _preCreate(data, options, user) {
|
||||||
|
const allowed = await super._preCreate(data, options, user);
|
||||||
|
if (allowed === false) return;
|
||||||
|
|
||||||
if (this.actor?.type === 'character') {
|
if (this.actor?.type === 'character') {
|
||||||
const dataUuid = data.uuid ?? data._stats.compendiumSource ?? `Item.${data._id}`;
|
const dataUuid = data.uuid ?? data._stats.compendiumSource ?? `Item.${data._id}`;
|
||||||
if (this.actor.system.class.subclass) {
|
if (this.actor.system.class.subclass) {
|
||||||
|
|
@ -85,8 +88,5 @@ export default class DHSubclass extends BaseDataItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const allowed = await super._preCreate(data, options, user);
|
|
||||||
if (allowed === false) return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,7 @@ export default class DamageRoll extends DHRoll {
|
||||||
if (config.data.parent.appliedEffects) {
|
if (config.data.parent.appliedEffects) {
|
||||||
// Bardic Rally
|
// Bardic Rally
|
||||||
const rallyChoices = config.data?.parent?.appliedEffects.reduce((a, c) => {
|
const rallyChoices = config.data?.parent?.appliedEffects.reduce((a, c) => {
|
||||||
const change = c.changes.find(ch => ch.key === 'system.bonuses.rally');
|
const change = c.system.changes.find(ch => ch.key === 'system.bonuses.rally');
|
||||||
if (change) a.push({ value: c.id, label: change.value });
|
if (change) a.push({ value: c.id, label: change.value });
|
||||||
return a;
|
return a;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
|
||||||
|
|
@ -249,12 +249,12 @@ export default class DHRoll extends Roll {
|
||||||
const changeKeys = this.getActionChangeKeys();
|
const changeKeys = this.getActionChangeKeys();
|
||||||
return (
|
return (
|
||||||
this.options.effects?.reduce((acc, effect) => {
|
this.options.effects?.reduce((acc, effect) => {
|
||||||
if (effect.changes.some(x => changeKeys.some(key => x.key.includes(key)))) {
|
if (effect.system.changes.some(x => changeKeys.some(key => x.key.includes(key)))) {
|
||||||
acc[effect.id] = {
|
acc[effect.id] = {
|
||||||
id: effect.id,
|
id: effect.id,
|
||||||
name: effect.name,
|
name: effect.name,
|
||||||
description: effect.description,
|
description: effect.description,
|
||||||
changes: effect.changes,
|
changes: effect.system.changes,
|
||||||
origEffect: effect,
|
origEffect: effect,
|
||||||
selected: !effect.disabled
|
selected: !effect.disabled
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ export default class DualityRoll extends D20Roll {
|
||||||
|
|
||||||
setRallyChoices() {
|
setRallyChoices() {
|
||||||
return this.data?.parent?.appliedEffects.reduce((a, c) => {
|
return this.data?.parent?.appliedEffects.reduce((a, c) => {
|
||||||
const change = c.changes.find(ch => ch.key === 'system.bonuses.rally');
|
const change = c.system.changes.find(ch => ch.key === 'system.bonuses.rally');
|
||||||
if (change) a.push({ value: c.id, label: change.value });
|
if (change) a.push({ value: c.id, label: change.value });
|
||||||
return a;
|
return a;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
@ -179,7 +179,7 @@ export default class DualityRoll extends D20Roll {
|
||||||
static async buildConfigure(config = {}, message = {}) {
|
static async buildConfigure(config = {}, message = {}) {
|
||||||
config.dialog ??= {};
|
config.dialog ??= {};
|
||||||
config.guaranteedCritical = config.data?.parent?.appliedEffects.reduce((a, c) => {
|
config.guaranteedCritical = config.data?.parent?.appliedEffects.reduce((a, c) => {
|
||||||
const change = c.changes.find(ch => ch.key === 'system.rules.roll.guaranteedCritical');
|
const change = c.system.changes.find(ch => ch.key === 'system.rules.roll.guaranteedCritical');
|
||||||
if (change) a = true;
|
if (change) a = true;
|
||||||
return a;
|
return a;
|
||||||
}, false);
|
}, false);
|
||||||
|
|
|
||||||
|
|
@ -109,17 +109,25 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect {
|
||||||
|
|
||||||
/**@inheritdoc*/
|
/**@inheritdoc*/
|
||||||
static applyField(model, change, field) {
|
static applyField(model, change, field) {
|
||||||
change.value = DhActiveEffect.getChangeValue(model, change, change.effect);
|
change.key = DhActiveEffect.getChangeKey(model, change, change.effect);
|
||||||
super.applyField(model, change, field);
|
super.applyField(model, change, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
|
static getChangeKey(model, change, effect) {
|
||||||
|
return DhActiveEffect.parseValue(change.key, model, change, effect);
|
||||||
|
}
|
||||||
|
|
||||||
static getChangeValue(model, change, effect) {
|
static getChangeValue(model, change, effect) {
|
||||||
let value = change.value;
|
return DhActiveEffect.parseValue(change.value, model, change, effect);
|
||||||
const isOriginTarget = value.toLowerCase().includes('origin.@');
|
}
|
||||||
|
|
||||||
|
static parseValue(value, model, change, effect) {
|
||||||
|
let key = value;
|
||||||
|
const isOriginTarget = key.toLowerCase().includes('origin.@');
|
||||||
let parseModel = model;
|
let parseModel = model;
|
||||||
if (isOriginTarget && effect.origin) {
|
if (isOriginTarget && effect.origin) {
|
||||||
value = change.value.replaceAll(/origin\.@/gi, '@');
|
key = change.key.replaceAll(/origin\.@/gi, '@');
|
||||||
try {
|
try {
|
||||||
const originEffect = foundry.utils.fromUuidSync(effect.origin);
|
const originEffect = foundry.utils.fromUuidSync(effect.origin);
|
||||||
const doc =
|
const doc =
|
||||||
|
|
@ -130,8 +138,8 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect {
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const evalValue = this.effectSafeEval(itemAbleRollParse(value, parseModel, effect.parent));
|
const evalValue = this.effectSafeEval(itemAbleRollParse(key, parseModel, effect.parent));
|
||||||
return evalValue ?? value;
|
return evalValue ?? key;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -415,7 +415,12 @@ export async function createEmbeddedItemWithEffects(actor, baseData, update) {
|
||||||
...baseData,
|
...baseData,
|
||||||
id: data.id,
|
id: data.id,
|
||||||
uuid: data.uuid,
|
uuid: data.uuid,
|
||||||
effects: data.effects?.map(effect => effect.toObject())
|
_uuid: data.uuid,
|
||||||
|
effects: data.effects?.map(effect => effect.toObject()),
|
||||||
|
_stats: {
|
||||||
|
...data._stats,
|
||||||
|
compendiumSource: data.pack ? `Compendium.${data.pack}.Item.${data.id}` : null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@
|
||||||
"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": "1.6.1",
|
"version": "2.0.0",
|
||||||
"compatibility": {
|
"compatibility": {
|
||||||
"minimum": "13.346",
|
"minimum": "14.353",
|
||||||
"verified": "13.351",
|
"verified": "14.353",
|
||||||
"maximum": "13"
|
"maximum": "14"
|
||||||
},
|
},
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
17
templates/sheets/activeEffect/change.hbs
Normal file
17
templates/sheets/activeEffect/change.hbs
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<li data-index="{{index}}">
|
||||||
|
<div class="key">
|
||||||
|
{{formInput fields.key name=change.keyPath value=change.key}}
|
||||||
|
</div>
|
||||||
|
<div class="type">
|
||||||
|
{{formInput fields.type name=change.typePath value=change.type localize=true}}
|
||||||
|
</div>
|
||||||
|
<div class="value">
|
||||||
|
{{formInput fields.value name=change.valuePath value=change.value elementType="input"}}
|
||||||
|
</div>
|
||||||
|
<div class="priority">
|
||||||
|
{{formInput fields.priority name=change.priorityPath value=change.priority placeholder=defaultPriority}}
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<button type="button" class="inline-control icon fa-solid fa-trash" data-action="deleteChange"></button>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
@ -1,31 +1,16 @@
|
||||||
<section class="tab changes{{#if tab.active}} active{{/if}}" data-group="{{tab.group}}" data-tab="{{tab.id}}">
|
<section class="tab changes{{#if tab.active}} active{{/if}}" data-group="{{tab.group}}" data-tab="{{tab.id}}">
|
||||||
<header>
|
<header>
|
||||||
<div class="key">{{localize "EFFECT.ChangeKey"}}</div>
|
<div class="key">{{localize "EFFECT.FIELDS.changes.element.key.label"}}</div>
|
||||||
<div class="mode">{{localize "EFFECT.ChangeMode"}}</div>
|
<div class="type">{{localize "EFFECT.FIELDS.changes.element.type.label"}}</div>
|
||||||
<div class="value">{{localize "EFFECT.ChangeValue"}}</div>
|
<div class="value">{{localize "EFFECT.FIELDS.changes.element.value.label"}}</div>
|
||||||
<div class="priority">{{localize "EFFECT.ChangePriority"}}</div>
|
<div class="priority">{{localize "EFFECT.FIELDS.changes.element.priority.label"}}</div>
|
||||||
<div class="controls"><a data-action="addChange"><i class="fa-regular fa-square-plus"></i></a></div>
|
<div class="controls">
|
||||||
|
<button type="button" class="inline-control icon fa-regular fa-square-plus" data-action="addChange"></button>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<ol class="scrollable" data-changes>
|
<ol class="scrollable" data-changes>
|
||||||
{{#each source.changes as |change i|}}
|
{{#each changes as |change|}}
|
||||||
{{#with ../fields.changes.element.fields as |changeFields|}}
|
{{{change}}}
|
||||||
<li data-index="{{i}}">
|
|
||||||
<div class="key">
|
|
||||||
<input type="text" class="effect-change-input" name="{{concat "changes." i ".key"}}" value="{{change.key}}" />
|
|
||||||
</div>
|
|
||||||
<div class="mode">
|
|
||||||
{{formInput changeFields.mode name=(concat "changes." i ".mode") value=change.mode choices=@root.modes}}
|
|
||||||
</div>
|
|
||||||
<div class="value">
|
|
||||||
{{formInput changeFields.value name=(concat "changes." i ".value") value=change.value}}
|
|
||||||
</div>
|
|
||||||
<div class="priority">
|
|
||||||
{{formInput changeFields.priority name=(concat "changes." i ".priority") value=change.priority
|
|
||||||
placeholder=(lookup ../../priorities change.mode)}}
|
|
||||||
</div>
|
|
||||||
<div class="controls"><a data-action="deleteChange"><i class="fa-solid fa-trash"></i></a></div>
|
|
||||||
</li>
|
|
||||||
{{/with}}
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ol>
|
</ol>
|
||||||
</section>
|
</section>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue