forked from GitHub-Mirrors/foundry-sw5e
Spot the link / entityClass error!
This commit is contained in:
parent
c9a9f75a5d
commit
5f5a145626
20 changed files with 1039 additions and 5635 deletions
|
@ -1,19 +1,26 @@
|
|||
import { TraitSelector } from "../apps/trait-selector.js";
|
||||
|
||||
import TraitSelector from "../apps/trait-selector.js";
|
||||
|
||||
/**
|
||||
* Override and extend the core ItemSheet implementation to handle D&D5E specific item types
|
||||
* @type {ItemSheet}
|
||||
* Override and extend the core ItemSheet implementation to handle specific item types
|
||||
* @extends {ItemSheet}
|
||||
*/
|
||||
export class ItemSheet5e extends ItemSheet {
|
||||
export default class ItemSheet5e extends ItemSheet {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
if ( this.object.data.type === "class" ) {
|
||||
this.options.width = 600;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
width: 560,
|
||||
height: 420,
|
||||
height: "auto",
|
||||
classes: ["sw5e", "sheet", "item"],
|
||||
resizable: false,
|
||||
resizable: true,
|
||||
scrollY: [".tab.details"],
|
||||
tabs: [{navSelector: ".tabs", contentSelector: ".sheet-body", initial: "description"}]
|
||||
});
|
||||
|
@ -33,8 +40,6 @@ export class ItemSheet5e extends ItemSheet {
|
|||
getData() {
|
||||
const data = super.getData();
|
||||
data.labels = this.item.labels;
|
||||
|
||||
// Include CONFIG values
|
||||
data.config = CONFIG.SW5E;
|
||||
|
||||
// Item Type, Status, and Details
|
||||
|
@ -42,15 +47,81 @@ export class ItemSheet5e extends ItemSheet {
|
|||
data.itemStatus = this._getItemStatus(data.item);
|
||||
data.itemProperties = this._getItemProperties(data.item);
|
||||
data.isPhysical = data.item.data.hasOwnProperty("quantity");
|
||||
|
||||
// Potential consumption targets
|
||||
data.abilityConsumptionTargets = this._getItemConsumptionTargets(data.item);
|
||||
|
||||
// Action Details
|
||||
data.hasAttackRoll = this.item.hasAttack;
|
||||
data.isHealing = data.item.data.actionType === "heal";
|
||||
data.isFlatDC = getProperty(data.item.data, "save.scaling") === "flat";
|
||||
data.isWeapon = data.item.type === "weapon";
|
||||
data.isLine = ["line", "wall"].includes(data.item.data.target?.type);
|
||||
|
||||
// Vehicles
|
||||
data.isCrewed = data.item.data.activation?.type === 'crew';
|
||||
data.isMountable = this._isItemMountable(data.item);
|
||||
return data;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get the valid item consumption targets which exist on the actor
|
||||
* @param {Object} item Item data for the item being displayed
|
||||
* @return {{string: string}} An object of potential consumption targets
|
||||
* @private
|
||||
*/
|
||||
_getItemConsumptionTargets(item) {
|
||||
const consume = item.data.consume || {};
|
||||
if ( !consume.type ) return [];
|
||||
const actor = this.item.actor;
|
||||
if ( !actor ) return {};
|
||||
|
||||
// Ammunition
|
||||
if ( consume.type === "ammo" ) {
|
||||
return actor.itemTypes.consumable.reduce((ammo, i) => {
|
||||
if ( i.data.data.consumableType === "ammo" ) {
|
||||
ammo[i.id] = `${i.name} (${i.data.data.quantity})`;
|
||||
}
|
||||
return ammo;
|
||||
}, {});
|
||||
}
|
||||
|
||||
// Attributes
|
||||
else if ( consume.type === "attribute" ) {
|
||||
const attributes = Object.values(CombatTrackerConfig.prototype.getAttributeChoices())[0]; // Bit of a hack
|
||||
return attributes.reduce((obj, a) => {
|
||||
obj[a] = a;
|
||||
return obj;
|
||||
}, {});
|
||||
}
|
||||
|
||||
// Materials
|
||||
else if ( consume.type === "material" ) {
|
||||
return actor.items.reduce((obj, i) => {
|
||||
if ( ["consumable", "loot"].includes(i.data.type) && !i.data.data.activation ) {
|
||||
obj[i.id] = `${i.name} (${i.data.data.quantity})`;
|
||||
}
|
||||
return obj;
|
||||
}, {});
|
||||
}
|
||||
|
||||
// Charges
|
||||
else if ( consume.type === "charges" ) {
|
||||
return actor.items.reduce((obj, i) => {
|
||||
const uses = i.data.data.uses || {};
|
||||
if ( uses.per && uses.max ) {
|
||||
const label = uses.per === "charges" ?
|
||||
` (${game.i18n.format("SW5E.AbilityUseChargesLabel", {value: uses.value})})` :
|
||||
` (${game.i18n.format("SW5E.AbilityUseConsumableLabel", {max: uses.max, per: uses.per})})`;
|
||||
obj[i.id] = i.name + label;
|
||||
}
|
||||
return obj;
|
||||
}, {})
|
||||
}
|
||||
else return {};
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
|
@ -63,10 +134,10 @@ export class ItemSheet5e extends ItemSheet {
|
|||
return CONFIG.SW5E.powerPreparationModes[item.data.preparation];
|
||||
}
|
||||
else if ( ["weapon", "equipment"].includes(item.type) ) {
|
||||
return item.data.equipped ? "Equipped" : "Unequipped";
|
||||
return game.i18n.localize(item.data.equipped ? "SW5E.Equipped" : "SW5E.Unequipped");
|
||||
}
|
||||
else if ( item.type === "tool" ) {
|
||||
return item.data.proficient ? "Proficient" : "Not Proficient";
|
||||
return game.i18n.localize(item.data.proficient ? "SW5E.Proficient" : "SW5E.NotProficient");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,8 +162,8 @@ export class ItemSheet5e extends ItemSheet {
|
|||
props.push(
|
||||
labels.components,
|
||||
labels.materials,
|
||||
item.data.components.concentration ? "Concentration" : null,
|
||||
item.data.components.ritual ? "Ritual" : null
|
||||
item.data.components.concentration ? game.i18n.localize("SW5E.Concentration") : null,
|
||||
item.data.components.ritual ? game.i18n.localize("SW5E.Ritual") : null
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -108,9 +179,6 @@ export class ItemSheet5e extends ItemSheet {
|
|||
else if ( item.type === "species" ) {
|
||||
|
||||
}
|
||||
<<<<<<< Updated upstream
|
||||
|
||||
=======
|
||||
else if ( item.type === "archetype" ) {
|
||||
|
||||
}
|
||||
|
@ -123,7 +191,6 @@ export class ItemSheet5e extends ItemSheet {
|
|||
|
||||
}
|
||||
|
||||
>>>>>>> Stashed changes
|
||||
// Action type
|
||||
if ( item.data.actionType ) {
|
||||
props.push(CONFIG.SW5E.itemActionTypes[item.data.actionType]);
|
||||
|
@ -143,9 +210,27 @@ export class ItemSheet5e extends ItemSheet {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Is this item a separate large object like a siege engine or vehicle
|
||||
* component that is usually mounted on fixtures rather than equipped, and
|
||||
* has its own AC and HP.
|
||||
* @param item
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
_isItemMountable(item) {
|
||||
const data = item.data;
|
||||
return (item.type === 'weapon' && data.weaponType === 'siege')
|
||||
|| (item.type === 'equipment' && data.armor.type === 'vehicle');
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
setPosition(position={}) {
|
||||
position.height = this._tabs[0].active === "details" ? "auto" : this.options.height;
|
||||
if ( !this._minimized ) {
|
||||
position.height = this._tabs[0].active === "details" ? "auto" : this.options.height;
|
||||
}
|
||||
return super.setPosition(position);
|
||||
}
|
||||
|
||||
|
@ -156,33 +241,12 @@ export class ItemSheet5e extends ItemSheet {
|
|||
/** @override */
|
||||
_updateObject(event, formData) {
|
||||
|
||||
// TODO: This can be removed once 0.7.x is release channel
|
||||
if ( !formData.data ) formData = expandObject(formData);
|
||||
|
||||
// Handle Damage Array
|
||||
let damage = Object.entries(formData).filter(e => e[0].startsWith("data.damage.parts"));
|
||||
formData["data.damage.parts"] = damage.reduce((arr, entry) => {
|
||||
let [i, j] = entry[0].split(".").slice(3);
|
||||
if ( !arr[i] ) arr[i] = [];
|
||||
arr[i][j] = entry[1];
|
||||
return arr;
|
||||
}, []);
|
||||
|
||||
// Handle armorproperties Array
|
||||
let armorproperties = Object.entries(formData).filter(e => e[0].startsWith("data.armorproperties.parts"));
|
||||
formData["data.armorproperties.parts"] = armorproperties.reduce((arr, entry) => {
|
||||
let [i, j] = entry[0].split(".").slice(3);
|
||||
if ( !arr[i] ) arr[i] = [];
|
||||
arr[i][j] = entry[1];
|
||||
return arr;
|
||||
}, []);
|
||||
|
||||
// Handle weaponproperties Array
|
||||
let weaponproperties = Object.entries(formData).filter(e => e[0].startsWith("data.weaponproperties.parts"));
|
||||
formData["data.weaponproperties.parts"] = weaponproperties.reduce((arr, entry) => {
|
||||
let [i, j] = entry[0].split(".").slice(3);
|
||||
if ( !arr[i] ) arr[i] = [];
|
||||
arr[i][j] = entry[1];
|
||||
return arr;
|
||||
}, []);
|
||||
|
||||
const damage = formData.data?.damage;
|
||||
if ( damage ) damage.parts = Object.values(damage?.parts || {}).map(d => [d[0] || "", d[1] || ""]);
|
||||
|
||||
// Update the Item
|
||||
super._updateObject(event, formData);
|
||||
|
@ -194,16 +258,7 @@ export class ItemSheet5e extends ItemSheet {
|
|||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
html.find(".damage-control").click(this._onDamageControl.bind(this));
|
||||
|
||||
// Activate any Trait Selectors
|
||||
html.find('.trait-selector.class-skills').click(this._onConfigureClassSkills.bind(this));
|
||||
|
||||
// Armor properties
|
||||
html.find(".armorproperties-control").click(this._onarmorpropertiesControl.bind(this));
|
||||
|
||||
// Weapon properties
|
||||
html.find(".weaponproperties-control").click(this._onweaponpropertiesControl.bind(this));
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -237,64 +292,6 @@ export class ItemSheet5e extends ItemSheet {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Add or remove a armorproperties part from the armorproperties formula
|
||||
* @param {Event} event The original click event
|
||||
* @return {Promise}
|
||||
* @private
|
||||
*/
|
||||
async _onarmorpropertiesControl(event) {
|
||||
event.preventDefault();
|
||||
const a = event.currentTarget;
|
||||
|
||||
// Add new armorproperties component
|
||||
if ( a.classList.contains("add-armorproperties") ) {
|
||||
await this._onSubmit(event); // Submit any unsaved changes
|
||||
const armorproperties = this.item.data.data.armorproperties;
|
||||
return this.item.update({"data.armorproperties.parts": armorproperties.parts.concat([["", ""]])});
|
||||
}
|
||||
|
||||
// Remove a armorproperties component
|
||||
if ( a.classList.contains("delete-armorproperties") ) {
|
||||
await this._onSubmit(event); // Submit any unsaved changes
|
||||
const li = a.closest(".armorproperties-part");
|
||||
const armorproperties = duplicate(this.item.data.data.armorproperties);
|
||||
armorproperties.parts.splice(Number(li.dataset.armorpropertiesPart), 1);
|
||||
return this.item.update({"data.armorproperties.parts": armorproperties.parts});
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Add or remove a weaponproperties part from the weaponproperties formula
|
||||
* @param {Event} event The original click event
|
||||
* @return {Promise}
|
||||
* @private
|
||||
*/
|
||||
async _onweaponpropertiesControl(event) {
|
||||
event.preventDefault();
|
||||
const a = event.currentTarget;
|
||||
|
||||
// Add new weaponproperties component
|
||||
if ( a.classList.contains("add-weaponproperties") ) {
|
||||
await this._onSubmit(event); // Submit any unsaved changes
|
||||
const weaponproperties = this.item.data.data.weaponproperties;
|
||||
return this.item.update({"data.weaponproperties.parts": weaponproperties.parts.concat([["", ""]])});
|
||||
}
|
||||
|
||||
// Remove a weaponproperties component
|
||||
if ( a.classList.contains("delete-weaponproperties") ) {
|
||||
await this._onSubmit(event); // Submit any unsaved changes
|
||||
const li = a.closest(".weaponproperties-part");
|
||||
const weaponproperties = duplicate(this.item.data.data.weaponproperties);
|
||||
weaponproperties.parts.splice(Number(li.dataset.weaponpropertiesPart), 1);
|
||||
return this.item.update({"data.weaponproperties.parts": weaponproperties.parts});
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Handle spawning the TraitSelector application which allows a checkbox of multiple trait options
|
||||
* @param {Event} event The click event which originated the selection
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue