mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-06-05 20:34:15 +02:00
[Fix] origin change values and prioritize item options (#1835)
Some checks are pending
Project CI / build (24.x) (push) Waiting to run
Some checks are pending
Project CI / build (24.x) (push) Waiting to run
* Fix origin key replacement and prioritize item options * Rename key to value * Some fixes * Attempt to always retrieve the source item for same actor origin * Fix getters in item roll data * Performance improvement * Allow apply to item system data * Replace implementation with shallow proxy * Add delete to the shallow proxy * Add proxy trap for the in operator --------- Co-authored-by: WBHarry <williambjrklund@gmail.com>
This commit is contained in:
parent
c82bcbeb01
commit
6d09c5504d
6 changed files with 70 additions and 37 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs';
|
import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs';
|
||||||
import DHItem from '../../documents/item.mjs';
|
import DHItem from '../../documents/item.mjs';
|
||||||
import { getScrollTextData } from '../../helpers/utils.mjs';
|
import { createShallowProxy, getScrollTextData } from '../../helpers/utils.mjs';
|
||||||
|
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
|
|
@ -180,8 +180,7 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
|
||||||
* @returns {object}
|
* @returns {object}
|
||||||
*/
|
*/
|
||||||
getRollData() {
|
getRollData() {
|
||||||
const data = { ...this };
|
return createShallowProxy(this);
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,12 @@
|
||||||
* @property {boolean} isInventoryItem- Indicates whether items of this type is a Inventory Item
|
* @property {boolean} isInventoryItem- Indicates whether items of this type is a Inventory Item
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addLinkedItemsDiff, getScrollTextData, updateLinkedItemApps } from '../../helpers/utils.mjs';
|
import {
|
||||||
|
addLinkedItemsDiff,
|
||||||
|
getScrollTextData,
|
||||||
|
createShallowProxy,
|
||||||
|
updateLinkedItemApps
|
||||||
|
} from '../../helpers/utils.mjs';
|
||||||
import { ActionsField } from '../fields/actionField.mjs';
|
import { ActionsField } from '../fields/actionField.mjs';
|
||||||
import FormulaField from '../fields/formulaField.mjs';
|
import FormulaField from '../fields/formulaField.mjs';
|
||||||
|
|
||||||
|
|
@ -159,8 +164,8 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
||||||
* @returns {object}
|
* @returns {object}
|
||||||
*/
|
*/
|
||||||
getRollData(options = {}) {
|
getRollData(options = {}) {
|
||||||
const actorRollData = this.actor?.getRollData() ?? {};
|
const data = this.actor?.getRollData() ?? {};
|
||||||
const data = { ...actorRollData, item: { ...this } };
|
data.item = createShallowProxy(this);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -169,27 +169,36 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect {
|
||||||
super._applyChangeUnguided(actor, change, changes, options);
|
super._applyChangeUnguided(actor, change, changes, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Recursively finds the first parent document of the given object */
|
||||||
|
static #resolveParentDocument(model, documentClass) {
|
||||||
|
return model instanceof documentClass
|
||||||
|
? model
|
||||||
|
: model.parent
|
||||||
|
? this.#resolveParentDocument(model.parent, documentClass)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
static getChangeValue(model, change, effect) {
|
static getChangeValue(model, change, effect) {
|
||||||
let key = change.value.toString();
|
let value = change.value.toString();
|
||||||
const isOriginTarget = key.toLowerCase().includes('origin.@');
|
const useOrigin = value.toLowerCase().includes('origin.@') && effect.origin;
|
||||||
let parseModel = model;
|
let origin = null;
|
||||||
if (isOriginTarget && effect.origin) {
|
if (effect.origin) {
|
||||||
key = change.key.replaceAll(/origin\.@/gi, '@');
|
if (useOrigin) value = value.replaceAll(/origin\.@/gi, '@');
|
||||||
try {
|
const originEffect = foundry.utils.fromUuidSync(effect.origin);
|
||||||
const originEffect = foundry.utils.fromUuidSync(effect.origin);
|
origin = this.#resolveParentDocument(originEffect, Item);
|
||||||
const doc =
|
|
||||||
originEffect.parent?.parent instanceof game.system.api.documents.DhpActor
|
|
||||||
? originEffect.parent
|
|
||||||
: originEffect.parent.parent;
|
|
||||||
if (doc) parseModel = doc;
|
|
||||||
} catch (_) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the actor and item documents. Note that actor roll data is inclusive of system roll data
|
||||||
|
const actor = this.#resolveParentDocument(model, Actor);
|
||||||
|
const item =
|
||||||
|
(useOrigin ? origin : null) ??
|
||||||
|
this.#resolveParentDocument(effect.parent, Item) ??
|
||||||
|
(origin?.actor === actor ? origin : null);
|
||||||
const stackingParsedValue = effect.system.stacking
|
const stackingParsedValue = effect.system.stacking
|
||||||
? Roll.replaceFormulaData(key, { stacks: effect.system.stacking.value })
|
? Roll.replaceFormulaData(value, { stacks: effect.system.stacking.value })
|
||||||
: key;
|
: value;
|
||||||
const evalValue = itemAbleRollParse(stackingParsedValue, parseModel, effect.parent);
|
const evalValue = this.effectSafeEval(itemAbleRollParse(stackingParsedValue, actor, item));
|
||||||
return evalValue ?? key;
|
return evalValue ?? value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs';
|
import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs';
|
||||||
import { LevelOptionType } from '../data/levelTier.mjs';
|
import { LevelOptionType } from '../data/levelTier.mjs';
|
||||||
import DHFeature from '../data/item/feature.mjs';
|
import DHFeature from '../data/item/feature.mjs';
|
||||||
import { createScrollText, damageKeyToNumber, getDamageKey } from '../helpers/utils.mjs';
|
import { createScrollText, damageKeyToNumber, getDamageKey, createShallowProxy } from '../helpers/utils.mjs';
|
||||||
import DhCompanionLevelUp from '../applications/levelup/companionLevelup.mjs';
|
import DhCompanionLevelUp from '../applications/levelup/companionLevelup.mjs';
|
||||||
import { ResourceUpdateMap } from '../data/action/baseAction.mjs';
|
import { ResourceUpdateMap } from '../data/action/baseAction.mjs';
|
||||||
import { abilities } from '../config/actorConfig.mjs';
|
import { abilities } from '../config/actorConfig.mjs';
|
||||||
|
|
@ -595,10 +595,7 @@ export default class DhpActor extends Actor {
|
||||||
|
|
||||||
/**@inheritdoc */
|
/**@inheritdoc */
|
||||||
getRollData() {
|
getRollData() {
|
||||||
const rollData = foundry.utils.deepClone(super.getRollData());
|
const rollData = createShallowProxy(super.getRollData());
|
||||||
/* system gets repeated infinately which causes issues when trying to use the data for document creation */
|
|
||||||
delete rollData.system;
|
|
||||||
|
|
||||||
rollData.id = this.id;
|
rollData.id = this.id;
|
||||||
rollData.name = this.name;
|
rollData.name = this.name;
|
||||||
rollData.system = this.system.getRollData();
|
rollData.system = this.system.getRollData();
|
||||||
|
|
|
||||||
|
|
@ -54,13 +54,7 @@ export default class DHItem extends foundry.documents.Item {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
getRollData(options = {}) {
|
getRollData(options = {}) {
|
||||||
let data;
|
let data = this.system.getRollData(options);
|
||||||
if (this.system.getRollData) data = this.system.getRollData(options);
|
|
||||||
else {
|
|
||||||
const actorRollData = this.actor?.getRollData(options) ?? {};
|
|
||||||
data = { ...actorRollData, item: { ...this.system } };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data?.item) {
|
if (data?.item) {
|
||||||
data.item.flags = { ...this.flags };
|
data.item.flags = { ...this.flags };
|
||||||
data.item.name = this.name;
|
data.item.name = this.name;
|
||||||
|
|
|
||||||
|
|
@ -372,10 +372,11 @@ export const itemAbleRollParse = (value, actor, item) => {
|
||||||
|
|
||||||
const isItemTarget = value.toLowerCase().includes('item.@');
|
const isItemTarget = value.toLowerCase().includes('item.@');
|
||||||
const slicedValue = isItemTarget ? value.replaceAll(/item\.@/gi, '@') : value;
|
const slicedValue = isItemTarget ? value.replaceAll(/item\.@/gi, '@') : value;
|
||||||
const model = isItemTarget ? item : actor;
|
const model = isItemTarget || item instanceof Item ? item : actor;
|
||||||
|
const rollData = isItemTarget || !model?.getRollData ? model : model.getRollData();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return Roll.replaceFormulaData(slicedValue, isItemTarget || !model?.getRollData ? model : model.getRollData());
|
return Roll.replaceFormulaData(slicedValue, rollData);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
@ -809,3 +810,31 @@ export function sortBy(arr, fn) {
|
||||||
};
|
};
|
||||||
return arr.sort(cmp);
|
return arr.sort(cmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a proxy that allows retrieval of top data but diverts updates to a different object.
|
||||||
|
* Generally used for roll data
|
||||||
|
*/
|
||||||
|
export function createShallowProxy(obj) {
|
||||||
|
if (obj._isShallowProxy) return obj;
|
||||||
|
|
||||||
|
const overrides = {};
|
||||||
|
return new Proxy(obj, {
|
||||||
|
get(target, prop, receiver) {
|
||||||
|
if (prop === '_isShallowProxy') return true;
|
||||||
|
if (prop in overrides) return overrides[prop];
|
||||||
|
return Reflect.get(target, prop, receiver);
|
||||||
|
},
|
||||||
|
set(_target, prop, newValue) {
|
||||||
|
overrides[prop] = newValue;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
deleteProperty(_target, prop) {
|
||||||
|
delete overrides[prop];
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
has(target, key) {
|
||||||
|
return key in overrides || key in target;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue