Update Core to 1.4.1

Update Core to 1.4.1 and internal Version to 1.4.1.R1-A8
This commit is contained in:
supervj 2021-08-06 16:38:15 -04:00
parent f16383841b
commit 5bb253d9c3
56 changed files with 5440 additions and 3827 deletions

View file

@ -0,0 +1,94 @@
/**
* Interface for managing a character's armor calculation.
* @extends {DocumentSheet}
*/
export default class ActorArmorConfig extends DocumentSheet {
/** @inheritdoc */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
id: "actor-armor-config",
classes: ["sw5e", "actor-armor-config"],
template: "systems/sw5e/templates/apps/actor-armor.html",
width: 320,
height: "auto"
});
}
/* -------------------------------------------- */
/** @inheritdoc */
get title() {
return `${game.i18n.localize("SW5E.ArmorConfig")}: ${this.document.name}`;
}
/* -------------------------------------------- */
/** @inheritdoc */
async getData() {
// Get actor AC data
const actorData = foundry.utils.deepClone(this.object.data.data);
const ac = foundry.utils.getProperty(actorData, "attributes.ac");
// Get configuration data for the calculation mode
let cfg = CONFIG.SW5E.armorClasses[ac.calc];
if (!cfg) {
ac.calc = "flat";
cfg = CONFIG.SW5E.armorClasses.flat;
}
// Return context data
return {
ac: ac,
calculations: CONFIG.SW5E.armorClasses,
value: this.object._computeArmorClass(actorData).value,
valueDisabled: !["flat", "natural"].includes(ac.calc),
formula: ac.calc === "custom" ? ac.formula : cfg.formula,
formulaDisabled: ac.calc !== "custom"
};
}
/* -------------------------------------------- */
/** @inheritdoc */
async _updateObject(event, formData) {
const ac = foundry.utils.expandObject(formData).ac;
return this.object.update({"data.attributes.ac": ac});
}
/* -------------------------------------------- */
/* Event Listeners and Handlers */
/* -------------------------------------------- */
/** @inheritdoc */
async _onChangeInput(event) {
await super._onChangeInput(event);
// Reference actor data
let actorData = this.object.toObject(false);
let ac = actorData.data.attributes.ac;
// Reference form data
const calc = this.form["ac.calc"].value;
const cfg = CONFIG.SW5E.armorClasses[calc];
const enableFlat = ["flat", "natural"].includes(calc);
// Handle changes to the calculation mode specifically
let formula = this.form["ac.formula"].value;
let flat = this.form["ac.flat"].value;
if (event.currentTarget.name === "ac.calc") {
formula = calc === "custom" ? ac.formula : cfg.formula;
if (enableFlat) flat = ac.flat;
}
// Recompute effective AC
actorData = foundry.utils.mergeObject(actorData, {"data.attributes.ac": {calc, formula}});
if (enableFlat) actorData.data.attributes.ac.flat = flat;
ac = this.object._computeArmorClass(actorData.data);
// Update fields
this.form["ac.formula"].value = ac.formula;
this.form["ac.formula"].disabled = calc !== "custom";
this.form["ac.flat"].value = enableFlat ? ac.flat : ac.value;
this.form["ac.flat"].disabled = !enableFlat;
}
}

View file

@ -99,7 +99,7 @@ export default class ActorSheetFlags extends DocumentSheet {
{name: "data.bonuses.power.techDC", label: "SW5E.BonusTechPowerDC"}
];
for (let b of bonuses) {
b.value = getProperty(this.object._data, b.name) || "";
b.value = getProperty(this.object.data._source, b.name) || "";
}
return bonuses;
}
@ -119,7 +119,7 @@ export default class ActorSheetFlags extends DocumentSheet {
for (let [k, v] of Object.entries(flags)) {
if ([undefined, null, "", false, 0].includes(v)) {
delete flags[k];
if (hasProperty(actor._data.flags, `sw5e.${k}`)) {
if (hasProperty(actor.data._source.flags, `sw5e.${k}`)) {
unset = true;
flags[`-=${k}`] = null;
}

View file

@ -0,0 +1,120 @@
import TraitSelector from "./trait-selector.js";
/**
* An application for selecting proficiencies with categories that can contain children.
*
* @extends {TraitSelector}
*/
export default class ProficiencySelector extends TraitSelector {
/** @inheritdoc */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
title: "Actor Proficiency Selection",
type: "",
sortCategories: false
});
}
/* -------------------------------------------- */
/** @inheritdoc */
async getData() {
const attr = foundry.utils.getProperty(this.object.data, this.attribute);
const value = this.options.valueKey ? foundry.utils.getProperty(attr, this.options.valueKey) ?? [] : attr;
this.options.choices = CONFIG.SW5E[`${this.options.type}Proficiencies`];
const data = super.getData();
const pack = game.packs.get(CONFIG.SW5E.sourcePacks.ITEMS);
const ids = CONFIG.SW5E[`${this.options.type}Ids`];
const map = CONFIG.SW5E[`${this.options.type}ProficienciesMap`];
if (ids !== undefined) {
const typeProperty = this.options.type !== "armor" ? `${this.options.type}Type` : `armor.type`;
for (const [key, id] of Object.entries(ids)) {
const item = await pack.getDocument(id);
let type = foundry.utils.getProperty(item.data.data, typeProperty);
if (map && map[type]) type = map[type];
const entry = {
label: item.name,
chosen: attr ? value.includes(key) : false
};
if (data.choices[type] === undefined) {
data.choices[key] = entry;
} else {
if (data.choices[type].children === undefined) {
data.choices[type].children = {};
}
data.choices[type].children[key] = entry;
}
}
}
if (this.options.type === "tool") {
data.choices["vehicle"].children = Object.entries(CONFIG.SW5E.vehicleTypes).reduce((obj, [key, label]) => {
obj[key] = {
label: label,
chosen: attr ? value.includes(key) : false
};
return obj;
}, {});
}
if (this.options.sortCategories) data.choices = this._sortObject(data.choices);
for (const category of Object.values(data.choices)) {
if (!category.children) continue;
category.children = this._sortObject(category.children);
}
return data;
}
/* -------------------------------------------- */
/**
* Take the provided object and sort by the "label" property.
*
* @param {object} object Object to be sorted.
* @return {object} Sorted object.
* @private
*/
_sortObject(object) {
return Object.fromEntries(Object.entries(object).sort((lhs, rhs) => lhs[1].label.localeCompare(rhs[1].label)));
}
/* -------------------------------------------- */
/** @inheritdoc */
activateListeners(html) {
super.activateListeners(html);
for (const checkbox of html[0].querySelectorAll("input[type='checkbox']")) {
if (checkbox.checked) this._onToggleCategory(checkbox);
}
}
/* -------------------------------------------- */
/** @inheritdoc */
async _onChangeInput(event) {
super._onChangeInput(event);
if (event.target.tagName === "INPUT") this._onToggleCategory(event.target);
}
/* -------------------------------------------- */
/**
* Enable/disable all children when a category is checked.
*
* @param {HTMLElement} checkbox Checkbox that was changed.
* @private
*/
_onToggleCategory(checkbox) {
const children = checkbox.closest("li")?.querySelector("ol");
if (!children) return;
for (const child of children.querySelectorAll("input[type='checkbox']")) {
child.checked = child.disabled = checkbox.checked;
}
}
}

View file

@ -0,0 +1,92 @@
/**
* Description for a single part of a property attribution.
*
* @typedef {object} AttributionDescription
* @property {string} label Descriptive label that will be displayed. If the label is in the form
* of an @ property, the system will try to turn it into a human-readable label.
* @property {number} mode Application mode for this step as defined in
* [CONST.ACTIVE_EFFECT_MODES](https://foundryvtt.com/api/module-constants.html#.ACTIVE_EFFECT_MODES).
* @property {number} value Value of this step.
*/
/**
* Interface for viewing what factors went into determining a specific property.
*
* @extends {DocumentSheet}
*/
export default class PropertyAttribution extends Application {
/**
* @param {Document} object - Object containing the property to be attributed.
* @param {object.<string, AttributionDescription[]>} attribution - Object containing all of the attribution data.
* @param {string} property - Dot separated path to the property.
*/
constructor(object, attribution, property, options = {}) {
super(options);
this.object = object;
this.attribution = attribution;
this.property = property;
}
/* -------------------------------------------- */
/** @inheritdoc */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
id: "property-attribution",
classes: ["sw5e", "property-attribution"],
template: "systems/sw5e/templates/apps/property-attribution.html",
width: 320,
height: "auto"
});
}
/* -------------------------------------------- */
/**
* Render this view as a tooltip rather than a whole window.
* @return {jQuery} HTML of the rendered tooltip.
*/
async renderTooltip() {
const data = this.getData(this.options);
let html = await this._renderInner(data);
html[0].classList.add("tooltip");
return html;
}
/* -------------------------------------------- */
getData() {
const property = foundry.utils.getProperty(this.object.data.data, this.property);
let total;
if (Number.isNumeric(property)) {
total = property;
} else if (typeof property === "object" && Number.isNumeric(property.value)) {
total = property.value;
}
const sources = foundry.utils.duplicate(this.attribution[this.property]);
return {
sources: sources.map((entry) => {
if (entry.label.startsWith("@")) {
entry.label = this.getPropertyLabel(entry.label.slice(1));
}
if (entry.mode === CONST.ACTIVE_EFFECT_MODES.ADD && entry.value < 0) {
entry.negative = true;
entry.value = entry.value * -1;
}
return entry;
}),
total: total
};
}
/* -------------------------------------------- */
getPropertyLabel(property) {
const parts = property.split(".");
if (parts[0] === "abilities" && parts[1]) {
return CONFIG.SW5E.abilities[parts[1]];
}
return property;
}
}

View file

@ -23,6 +23,13 @@ export default class TraitSelector extends DocumentSheet {
/* -------------------------------------------- */
/** @inheritdoc */
get title() {
return this.options.title || super.title;
}
/* -------------------------------------------- */
/**
* Return a reference to the target attribute
* @type {string}
@ -37,8 +44,8 @@ export default class TraitSelector extends DocumentSheet {
getData() {
const attr = foundry.utils.getProperty(this.object.data, this.attribute);
const o = this.options;
const value = o.valueKey ? attr[o.valueKey] ?? [] : attr;
const custom = o.customKey ? attr[o.customKey] ?? "" : "";
const value = o.valueKey ? foundry.utils.getProperty(attr, o.valueKey) ?? [] : attr;
const custom = o.customKey ? foundry.utils.getProperty(attr, o.customKey) ?? "" : "";
// Populate choices
const choices = Object.entries(o.choices).reduce((obj, e) => {