worldbuilding/module/actor.js
Matt Smith 8b958dd232 10: Refactor actor sheet code
- Refactored actor-sheet.js to move most of its logic into a separate
  helper.js module as static methods on a new SimpleHelper class. This
  doesn't add anything functional at the moment, but it's in
  preparation of re-using the same code for the item-sheet.js file.
2020-10-06 17:20:00 +00:00

228 lines
7.9 KiB
JavaScript

import { EntitySheetHelper } from "./helper.js";
/**
* Extend the base Actor entity by defining a custom roll data structure which is ideal for the Simple system.
* @extends {Actor}
*/
export class SimpleActor extends Actor {
/** @override */
prepareData() {
super.prepareData();
this.data.data.groups = this.data.data.groups || {};
this.data.data.attributes = this.data.data.attributes || {};
}
/* -------------------------------------------- */
/** @override */
getRollData() {
const data = super.getRollData();
const shorthand = game.settings.get("worldbuilding", "macroShorthand");
const formulaAttributes = [];
const itemAttributes = [];
// Handle formula attributes when the short syntax is disabled.
this._applyShorthand(data, formulaAttributes, shorthand);
// Map all items data using their slugified names
this._applyItems(data, itemAttributes, shorthand);
// Evaluate formula replacements on items.
this._applyItemsFormulaReplacements(data, itemAttributes, shorthand);
// Evaluate formula attributes after all other attributes have been handled, including items.
this._applyFormulaReplacements(data, formulaAttributes, shorthand);
// Remove the attributes if necessary.
if ( !!shorthand ) {
delete data.attributes;
delete data.attr;
delete data.abil;
delete data.groups;
}
return data;
}
/**
* Apply shorthand syntax to actor roll data.
* @param {Object} data The actor's data object.
* @param {Array} formulaAttributes Array of attributes that are derived formulas.
* @param {Boolean} shorthand Whether or not the shorthand syntax is used.
*/
_applyShorthand(data, formulaAttributes, shorthand) {
// Handle formula attributes when the short syntax is disabled.
for ( let [k, v] of Object.entries(data.attributes) ) {
// Make an array of formula attributes for later reference.
if ( v.dtype == "Formula" ) formulaAttributes.push(k);
// Add shortened version of the attributes.
if ( !!shorthand ) {
if ( !(k in data) ) {
// Non-grouped attributes.
if ( v.dtype ) {
data[k] = v.value;
}
// Grouped attributes.
else {
data[k] = {};
for ( let [gk, gv] of Object.entries(v) ) {
data[k][gk] = gv.value;
if ( gv.dtype == "Formula" ) formulaAttributes.push(`${k}.${gk}`);
}
}
}
}
}
}
/**
* Add items to the actor roll data object. Handles regular and shorthand
* syntax, and calculates derived formula attributes on the items.
* @param {Object} data The actor's data object.
* @param {Boolean} shorthand Whether or not the shorthand syntax is used.
*/
_applyItems(data, itemAttributes, shorthand) {
// Map all items data using their slugified names
data.items = this.data.items.reduce((obj, i) => {
let key = i.name.slugify({strict: true});
let itemData = duplicate(i.data);
// Add items to shorthand and note which ones are formula attributes.
for ( let [k, v] of Object.entries(itemData.attributes) ) {
// When building the attribute list, prepend the item name for later use.
if ( v.dtype == "Formula" ) itemAttributes.push(`${key}..${k}`);
// Add shortened version of the attributes.
if ( !!shorthand ) {
if ( !(k in itemData) ) {
// Non-grouped item attributes.
if ( v.dtype ) {
itemData[k] = v.value;
}
// Grouped item attributes.
else {
if ( !itemData[k] ) itemData[k] = {};
for ( let [gk, gv] of Object.entries(v) ) {
itemData[k][gk] = gv.value;
if ( gv.dtype == "Formula" ) itemAttributes.push(`${key}..${k}.${gk}`);
}
}
}
}
// Handle non-shorthand version of grouped attributes.
else {
if ( !v.dtype ) {
if ( !itemData[k] ) itemData[k] = {};
for ( let [gk, gv] of Object.entries(v) ) {
itemData[k][gk] = gv.value;
if ( gv.dtype == "Formula" ) itemAttributes.push(`${key}..${k}.${gk}`);
}
}
}
}
// Delete the original attributes key if using the shorthand syntax.
if ( !!shorthand ) {
delete itemData.attributes;
}
obj[key] = itemData;
return obj;
}, {});
}
_applyItemsFormulaReplacements(data, itemAttributes, shorthand) {
for ( let k of itemAttributes ) {
// Get the item name and separate the key.
let item = null;
let itemKey = k.split('..');
item = itemKey[0];
k = itemKey[1];
// Handle group keys.
let gk = null;
if ( k.includes('.') ) {
let attrKey = k.split('.');
k = attrKey[0];
gk = attrKey[1];
}
let formula = '';
if ( !!shorthand ) {
// Handle grouped attributes first.
if ( data.items[item][k][gk] ) {
formula = data.items[item][k][gk];
data.items[item][k][gk] = EntitySheetHelper.replaceData(formula.replace('@item.', `@items.${item}.`), data, {missing: "0"});
}
// Handle non-grouped attributes.
else if ( data.items[item][k] ) {
formula = data.items[item][k];
data.items[item][k] = EntitySheetHelper.replaceData(formula.replace('@item.', `@items.${item}.`), data, {missing: "0"});
}
}
else {
// Handle grouped attributes first.
if ( data.items[item]['attributes'][k][gk] ) {
formula = data.items[item]['attributes'][k][gk]['value'];
data.items[item]['attributes'][k][gk]['value'] = EntitySheetHelper.replaceData(formula.replace('@item.', `@items.${item}.attributes.`), data, {missing: "0"});
}
// Handle non-grouped attributes.
else if ( data.items[item]['attributes'][k]['value'] ) {
formula = data.items[item]['attributes'][k]['value'];
data.items[item]['attributes'][k]['value'] = EntitySheetHelper.replaceData(formula.replace('@item.', `@items.${item}.attributes.`), data, {missing: "0"});
}
}
}
}
/**
* Apply replacements for derived formula attributes.
* @param {Object} data The actor's data object.
* @param {Array} formulaAttributes Array of attributes that are derived formulas.
* @param {Boolean} shorthand Whether or not the shorthand syntax is used.
*/
_applyFormulaReplacements(data, formulaAttributes, shorthand) {
// Evaluate formula attributes after all other attributes have been handled,
// including items.
for ( let k of formulaAttributes ) {
// Grouped attributes are included as `group.attr`, so we need to split
// them into new keys.
let attr = null;
if ( k.includes('.') ) {
let attrKey = k.split('.');
k = attrKey[0];
attr = attrKey[1];
}
// Non-grouped attributes.
if ( data.attributes[k]?.value ) {
data.attributes[k].value = EntitySheetHelper.replaceData(data.attributes[k].value, data, {missing: "0"});
// TODO: Replace with:
// data.attributes[k].value = Roll.replaceFormulaData(data.attributes[k].value, data, {missing: "0"});
}
// Grouped attributes.
else {
if ( attr ) {
data.attributes[k][attr].value = EntitySheetHelper.replaceData(data.attributes[k][attr].value, data, {missing: "0"});
}
}
// Duplicate values to shorthand.
if ( !!shorthand ) {
// Non-grouped attributes.
if ( data.attributes[k]?.value ) {
data[k] = data.attributes[k].value;
}
// Grouped attributes.
else {
if ( attr ) {
// Initialize a group key in case it doesn't exist.
if ( !data[k] ) {
data[k] = {};
}
data[k][attr] = data.attributes[k][attr].value;
}
}
}
}
}
}