mirror of
https://github.com/RoY7x/worldbuilding.git
synced 2025-04-30 02:31:41 -04:00
263 lines
9.2 KiB
JavaScript
263 lines
9.2 KiB
JavaScript
import { EntitySheetHelper } from "./helper.js";
|
|
|
|
/**
|
|
* Extend the base Actor document to support attributes and groups with a custom template creation dialog.
|
|
* @extends {Actor}
|
|
*/
|
|
export class SimpleActor extends Actor {
|
|
|
|
/** @inheritdoc */
|
|
prepareDerivedData() {
|
|
super.prepareDerivedData();
|
|
this.system.groups = this.system.groups || {};
|
|
this.system.attributes = this.system.attributes || {};
|
|
EntitySheetHelper.clampResourceValues(this.system.attributes);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
/** @override */
|
|
static async createDialog(data={}, options={}) {
|
|
return EntitySheetHelper.createDialog.call(this, data, options);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
/**
|
|
* Is this Actor used as a template for other Actors?
|
|
* @type {boolean}
|
|
*/
|
|
get isTemplate() {
|
|
return !!this.getFlag("worldbuilding", "isTemplate");
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
/* Roll Data Preparation */
|
|
/* -------------------------------------------- */
|
|
|
|
/** @inheritdoc */
|
|
getRollData() {
|
|
|
|
// Copy the actor's system data
|
|
const data = this.toObject(false).system;
|
|
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 item 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.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 {string[]} itemAttributes
|
|
* @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.items.reduce((obj, item) => {
|
|
const key = item.name.slugify({strict: true});
|
|
const itemData = item.toObject(false).system;
|
|
|
|
// 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] !== undefined ) {
|
|
formula = data.items[item][k][gk].replace('@item.', `@items.${item}.`);
|
|
data.items[item][k][gk] = Roll.replaceFormulaData(formula, data);
|
|
}
|
|
// Handle non-grouped attributes.
|
|
else if ( data.items[item][k] ) {
|
|
formula = data.items[item][k].replace('@item.', `@items.${item}.`);
|
|
data.items[item][k] = Roll.replaceFormulaData(formula, data);
|
|
}
|
|
}
|
|
else {
|
|
// Handle grouped attributes first.
|
|
if ( data.items[item]['attributes'][k][gk] ) {
|
|
formula = data.items[item]['attributes'][k][gk]['value'].replace('@item.', `@items.${item}.attributes.`);
|
|
data.items[item]['attributes'][k][gk]['value'] = Roll.replaceFormulaData(formula, data);
|
|
}
|
|
// Handle non-grouped attributes.
|
|
else if ( data.items[item]['attributes'][k]['value'] ) {
|
|
formula = data.items[item]['attributes'][k]['value'].replace('@item.', `@items.${item}.attributes.`);
|
|
data.items[item]['attributes'][k]['value'] = Roll.replaceFormulaData(formula, data);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
/**
|
|
* 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 = Roll.replaceFormulaData(String(data.attributes[k].value), data);
|
|
}
|
|
// Grouped attributes.
|
|
else if ( attr ) {
|
|
data.attributes[k][attr].value = Roll.replaceFormulaData(String(data.attributes[k][attr].value), data);
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
/** @inheritdoc */
|
|
async modifyTokenAttribute(attribute, value, isDelta = false, isBar = true) {
|
|
const current = foundry.utils.getProperty(this.system, attribute);
|
|
if ( !isBar || !isDelta || (current?.dtype !== "Resource") ) {
|
|
return super.modifyTokenAttribute(attribute, value, isDelta, isBar);
|
|
}
|
|
const updates = {[`system.${attribute}.value`]: Math.clamped(current.value + value, current.min, current.max)};
|
|
const allowed = Hooks.call("modifyTokenAttribute", {attribute, value, isDelta, isBar}, updates);
|
|
return allowed !== false ? this.update(updates) : this;
|
|
}
|
|
}
|