const fields = foundry.data.fields; export default class CostField extends fields.ArrayField { constructor(options = {}, context = {}) { const element = new fields.SchemaField({ key: new fields.StringField({ nullable: false, required: true, initial: 'hope' }), keyIsID: new fields.BooleanField(), value: new fields.NumberField({ nullable: true, initial: 1 }), scalable: new fields.BooleanField({ initial: false }), step: new fields.NumberField({ nullable: true, initial: null }) }); super(element, options, context); } static prepareConfig(config) { const costs = this.cost?.length ? foundry.utils.deepClone(this.cost) : []; config.costs = CostField.calcCosts.call(this, costs); const hasCost = CostField.hasCost.call(this, config.costs); if (config.isFastForward && !hasCost) return ui.notifications.warn("You don't have the resources to use that action."); return hasCost; } static calcCosts(costs) { // console.log(costs, CostField.getResources.call(this, costs)); const resources = CostField.getResources.call(this, costs); return costs.map(c => { c.scale = c.scale ?? 1; c.step = c.step ?? 1; c.total = c.value + (c.scale - 1) * c.step; c.enabled = c.hasOwnProperty('enabled') ? c.enabled : true; c.max = c.key === 'fear' ? game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear) : resources[c.key].isReversed ? resources[c.key].max : resources[c.key].value; if (c.scalable) c.maxStep = Math.floor(c.max / c.step); return c; }); } static hasCost(costs) { const realCosts = CostField.getRealCosts.call(this, costs), hasFearCost = realCosts.findIndex(c => c.key === 'fear'); if (hasFearCost > -1) { const fearCost = realCosts.splice(hasFearCost, 1)[0]; if ( !game.user.isGM || fearCost.total > game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear) ) return false; } /* isReversed is a sign that the resource is inverted, IE it counts upwards instead of down */ const resources = CostField.getResources.call(this, realCosts); return realCosts.reduce( (a, c) => !resources[c.key] ? a : a && resources[c.key].isReversed ? resources[c.key].value + (c.total ?? c.value) <= resources[c.key].max : resources[c.key]?.value >= (c.total ?? c.value), true ); } static getResources(costs) { const actorResources = this.actor.system.resources; const itemResources = {}; for (let itemResource of costs) { if (itemResource.keyIsID) { itemResources[itemResource.key] = { value: this.parent.resource.value ?? 0, max: CostField.formatMax.call(this, this.parent?.resource?.max) }; } } return { ...actorResources, ...itemResources }; } static getRealCosts(costs) { const realCosts = costs?.length ? costs.filter(c => c.enabled) : []; return realCosts; } static formatMax(max) { max ??= 0; if (isNaN(max)) { const roll = Roll.replaceFormulaData(max, this.getRollData()); max = roll.total; } return Number(max); } }