forked from GitHub-Mirrors/foundry-sw5e
Fully split force and tech powers into their own sheets
This commit is contained in:
parent
70d399e8f6
commit
1ce2e92ccd
18 changed files with 285 additions and 318 deletions
|
@ -64,26 +64,6 @@ export default class Item5e extends Item {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Is the Item a force power
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isForcePower() {
|
||||
return ["lgt", "drk", "uni"].includes(this.data.data.school);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Is the Item a tech power
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isTechPower() {
|
||||
return ["tec"].includes(this.data.data.school);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Does the Item implement an attack roll as part of its usage
|
||||
* @type {boolean}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import TraitSelector from "../apps/trait-selector.js";
|
||||
import {onManageActiveEffect, prepareActiveEffectCategories} from "../effects.js";
|
||||
import { onManageActiveEffect, prepareActiveEffectCategories } from "../effects.js";
|
||||
|
||||
/**
|
||||
* Override and extend the core ItemSheet implementation to handle specific item types
|
||||
|
@ -10,8 +10,8 @@ export default class ItemSheet5e extends ItemSheet {
|
|||
super(...args);
|
||||
|
||||
// Expand the default size of the class sheet
|
||||
if ( this.object.data.type === "class" ) {
|
||||
this.options.width = this.position.width = 600;
|
||||
if (this.object.data.type === "class") {
|
||||
this.options.width = this.position.width = 600;
|
||||
this.options.height = this.position.height = 680;
|
||||
}
|
||||
}
|
||||
|
@ -19,14 +19,14 @@ export default class ItemSheet5e extends ItemSheet {
|
|||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
width: 560,
|
||||
height: 400,
|
||||
classes: ["sw5e", "sheet", "item"],
|
||||
resizable: true,
|
||||
scrollY: [".tab.details"],
|
||||
tabs: [{navSelector: ".tabs", contentSelector: ".sheet-body", initial: "description"}]
|
||||
tabs: [{ navSelector: ".tabs", contentSelector: ".sheet-body", initial: "description" }]
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -55,17 +55,17 @@ export default class ItemSheet5e extends ItemSheet {
|
|||
// Potential consumption targets
|
||||
data.abilityConsumptionTargets = this._getItemConsumptionTargets(data.item);
|
||||
|
||||
// Action Details
|
||||
// Action Detail
|
||||
data.hasAttackRoll = this.item.hasAttack;
|
||||
data.isHealing = data.item.data.actionType === "heal";
|
||||
data.isFlatDC = getProperty(data.item.data, "save.scaling") === "flat";
|
||||
data.isLine = ["line", "wall"].includes(data.item.data.target?.type);
|
||||
|
||||
// Original maximum uses formula
|
||||
if ( this.item._data.data?.uses?.max ) data.data.uses.max = this.item._data.data.uses.max;
|
||||
if (this.item._data.data?.uses?.max) data.data.uses.max = this.item._data.data.uses.max;
|
||||
|
||||
// Vehicles
|
||||
data.isCrewed = data.item.data.activation?.type === 'crew';
|
||||
data.isCrewed = data.item.data.activation?.type === "crew";
|
||||
data.isMountable = this._isItemMountable(data.item);
|
||||
|
||||
// Prepare Active Effects
|
||||
|
@ -83,22 +83,25 @@ export default class ItemSheet5e extends ItemSheet {
|
|||
*/
|
||||
_getItemConsumptionTargets(item) {
|
||||
const consume = item.data.consume || {};
|
||||
if ( !consume.type ) return [];
|
||||
if (!consume.type) return [];
|
||||
const actor = this.item.actor;
|
||||
if ( !actor ) return {};
|
||||
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;
|
||||
}, {[item._id]: `${item.name} (${item.data.quantity})`});
|
||||
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;
|
||||
},
|
||||
{ [item._id]: `${item.name} (${item.data.quantity})` }
|
||||
);
|
||||
}
|
||||
|
||||
// Attributes
|
||||
else if ( consume.type === "attribute" ) {
|
||||
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;
|
||||
|
@ -107,9 +110,9 @@ export default class ItemSheet5e extends ItemSheet {
|
|||
}
|
||||
|
||||
// Materials
|
||||
else if ( consume.type === "material" ) {
|
||||
else if (consume.type === "material") {
|
||||
return actor.items.reduce((obj, i) => {
|
||||
if ( ["consumable", "loot"].includes(i.data.type) && !i.data.data.activation ) {
|
||||
if (["consumable", "loot"].includes(i.data.type) && !i.data.data.activation) {
|
||||
obj[i.id] = `${i.name} (${i.data.data.quantity})`;
|
||||
}
|
||||
return obj;
|
||||
|
@ -117,25 +120,24 @@ export default class ItemSheet5e extends ItemSheet {
|
|||
}
|
||||
|
||||
// Charges
|
||||
else if ( consume.type === "charges" ) {
|
||||
else if (consume.type === "charges") {
|
||||
return actor.items.reduce((obj, i) => {
|
||||
|
||||
// Limited-use items
|
||||
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})})`;
|
||||
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;
|
||||
}
|
||||
|
||||
// Recharging items
|
||||
const recharge = i.data.data.recharge || {};
|
||||
if ( recharge.value ) obj[i.id] = `${i.name} (${game.i18n.format("SW5E.Recharge")})`;
|
||||
if (recharge.value) obj[i.id] = `${i.name} (${game.i18n.format("SW5E.Recharge")})`;
|
||||
return obj;
|
||||
}, {})
|
||||
}
|
||||
else return {};
|
||||
}, {});
|
||||
} else return {};
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -146,13 +148,11 @@ export default class ItemSheet5e extends ItemSheet {
|
|||
* @private
|
||||
*/
|
||||
_getItemStatus(item) {
|
||||
if ( item.type === "power" ) {
|
||||
if (item.type === "power") {
|
||||
return CONFIG.SW5E.powerPreparationModes[item.data.preparation];
|
||||
}
|
||||
else if ( ["weapon", "equipment"].includes(item.type) ) {
|
||||
} else if (["weapon", "equipment"].includes(item.type)) {
|
||||
return game.i18n.localize(item.data.equipped ? "SW5E.Equipped" : "SW5E.Unequipped");
|
||||
}
|
||||
else if ( item.type === "tool" ) {
|
||||
} else if (item.type === "tool") {
|
||||
return game.i18n.localize(item.data.proficient ? "SW5E.Proficient" : "SW5E.NotProficient");
|
||||
}
|
||||
}
|
||||
|
@ -168,67 +168,50 @@ export default class ItemSheet5e extends ItemSheet {
|
|||
const props = [];
|
||||
const labels = this.item.labels;
|
||||
|
||||
if ( item.type === "weapon" ) {
|
||||
props.push(...Object.entries(item.data.properties)
|
||||
.filter(e => e[1] === true)
|
||||
.map(e => CONFIG.SW5E.weaponProperties[e[0]]));
|
||||
}
|
||||
|
||||
else if ( item.type === "power" ) {
|
||||
if (item.type === "weapon") {
|
||||
props.push(
|
||||
...Object.entries(item.data.properties)
|
||||
.filter((e) => e[1] === true)
|
||||
.map((e) => CONFIG.SW5E.weaponProperties[e[0]])
|
||||
);
|
||||
} else if (item.type === "power") {
|
||||
props.push(
|
||||
labels.components,
|
||||
labels.materials,
|
||||
item.data.components.concentration ? game.i18n.localize("SW5E.Concentration") : null,
|
||||
item.data.components.ritual ? game.i18n.localize("SW5E.Ritual") : null
|
||||
)
|
||||
}
|
||||
|
||||
else if ( item.type === "equipment" ) {
|
||||
);
|
||||
} else if (item.type === "equipment") {
|
||||
props.push(CONFIG.SW5E.equipmentTypes[item.data.armor.type]);
|
||||
props.push(labels.armor);
|
||||
} else if (item.type === "feat") {
|
||||
props.push(labels.featType);
|
||||
} else if (item.type === "species") {
|
||||
//props.push(labels.species);
|
||||
} else if (item.type === "archetype") {
|
||||
//props.push(labels.archetype);
|
||||
} else if (item.type === "background") {
|
||||
//props.push(labels.background);
|
||||
} else if (item.type === "classfeature") {
|
||||
//props.push(labels.classfeature);
|
||||
} else if (item.type === "fightingmastery") {
|
||||
//props.push(labels.fightingmastery);
|
||||
} else if (item.type === "fightingstyle") {
|
||||
//props.push(labels.fightingstyle);
|
||||
} else if (item.type === "lightsaberform") {
|
||||
//props.push(labels.lightsaberform);
|
||||
}
|
||||
|
||||
else if ( item.type === "feat" ) {
|
||||
props.push(labels.featType);
|
||||
}
|
||||
|
||||
else if ( item.type === "species" ) {
|
||||
//props.push(labels.species);
|
||||
}
|
||||
else if ( item.type === "archetype" ) {
|
||||
//props.push(labels.archetype);
|
||||
}
|
||||
else if ( item.type === "background" ) {
|
||||
//props.push(labels.background);
|
||||
}
|
||||
else if ( item.type === "classfeature" ) {
|
||||
//props.push(labels.classfeature);
|
||||
}
|
||||
else if ( item.type === "fightingmastery" ) {
|
||||
//props.push(labels.fightingmastery);
|
||||
}
|
||||
else if ( item.type === "fightingstyle" ) {
|
||||
//props.push(labels.fightingstyle);
|
||||
}
|
||||
else if ( item.type === "lightsaberform" ) {
|
||||
//props.push(labels.lightsaberform);
|
||||
}
|
||||
|
||||
// Action type
|
||||
if ( item.data.actionType ) {
|
||||
if (item.data.actionType) {
|
||||
props.push(CONFIG.SW5E.itemActionTypes[item.data.actionType]);
|
||||
}
|
||||
|
||||
// Action usage
|
||||
if ( (item.type !== "weapon") && item.data.activation && !isObjectEmpty(item.data.activation) ) {
|
||||
props.push(
|
||||
labels.activation,
|
||||
labels.range,
|
||||
labels.target,
|
||||
labels.duration
|
||||
)
|
||||
if (item.type !== "weapon" && item.data.activation && !isObjectEmpty(item.data.activation)) {
|
||||
props.push(labels.activation, labels.range, labels.target, labels.duration);
|
||||
}
|
||||
return props.filter(p => !!p);
|
||||
return props.filter((p) => !!p);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -243,36 +226,37 @@ export default class ItemSheet5e extends ItemSheet {
|
|||
*/
|
||||
_isItemMountable(item) {
|
||||
const data = item.data;
|
||||
return (item.type === 'weapon' && data.weaponType === 'siege')
|
||||
|| (item.type === 'equipment' && data.armor.type === 'vehicle');
|
||||
return (
|
||||
(item.type === "weapon" && data.weaponType === "siege") ||
|
||||
(item.type === "equipment" && data.armor.type === "vehicle")
|
||||
);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
setPosition(position={}) {
|
||||
if ( !(this._minimized || position.height) ) {
|
||||
position.height = (this._tabs[0].active === "details") ? "auto" : this.options.height;
|
||||
setPosition(position = {}) {
|
||||
if (!(this._minimized || position.height)) {
|
||||
position.height = this._tabs[0].active === "details" ? "auto" : this.options.height;
|
||||
}
|
||||
return super.setPosition(position);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Form Submission */
|
||||
/* -------------------------------------------- */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
_getSubmitData(updateData={}) {
|
||||
|
||||
_getSubmitData(updateData = {}) {
|
||||
// Create the expanded update data object
|
||||
const fd = new FormDataExtended(this.form, {editors: this.editors});
|
||||
const fd = new FormDataExtended(this.form, { editors: this.editors });
|
||||
let data = fd.toObject();
|
||||
if ( updateData ) data = mergeObject(data, updateData);
|
||||
if (updateData) data = mergeObject(data, updateData);
|
||||
else data = expandObject(data);
|
||||
|
||||
// Handle Damage array
|
||||
const damage = data.data?.damage;
|
||||
if ( damage ) damage.parts = Object.values(damage?.parts || {}).map(d => [d[0] || "", d[1] || ""]);
|
||||
if (damage) damage.parts = Object.values(damage?.parts || {}).map((d) => [d[0] || "", d[1] || ""]);
|
||||
|
||||
// Return the flattened submission data
|
||||
return flattenObject(data);
|
||||
|
@ -283,12 +267,15 @@ export default class ItemSheet5e extends ItemSheet {
|
|||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
if ( this.isEditable ) {
|
||||
if (this.isEditable) {
|
||||
html.find(".damage-control").click(this._onDamageControl.bind(this));
|
||||
html.find('.trait-selector.class-skills').click(this._onConfigureClassSkills.bind(this));
|
||||
html.find(".effect-control").click(ev => {
|
||||
if ( this.item.isOwned ) return ui.notifications.warn("Managing Active Effects within an Owned Item is not currently supported and will be added in a subsequent update.")
|
||||
onManageActiveEffect(ev, this.item)
|
||||
html.find(".trait-selector.class-skills").click(this._onConfigureClassSkills.bind(this));
|
||||
html.find(".effect-control").click((ev) => {
|
||||
if (this.item.isOwned)
|
||||
return ui.notifications.warn(
|
||||
"Managing Active Effects within an Owned Item is not currently supported and will be added in a subsequent update."
|
||||
);
|
||||
onManageActiveEffect(ev, this.item);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -306,19 +293,19 @@ export default class ItemSheet5e extends ItemSheet {
|
|||
const a = event.currentTarget;
|
||||
|
||||
// Add new damage component
|
||||
if ( a.classList.contains("add-damage") ) {
|
||||
await this._onSubmit(event); // Submit any unsaved changes
|
||||
if (a.classList.contains("add-damage")) {
|
||||
await this._onSubmit(event); // Submit any unsaved changes
|
||||
const damage = this.item.data.data.damage;
|
||||
return this.item.update({"data.damage.parts": damage.parts.concat([["", ""]])});
|
||||
return this.item.update({ "data.damage.parts": damage.parts.concat([["", ""]]) });
|
||||
}
|
||||
|
||||
// Remove a damage component
|
||||
if ( a.classList.contains("delete-damage") ) {
|
||||
await this._onSubmit(event); // Submit any unsaved changes
|
||||
if (a.classList.contains("delete-damage")) {
|
||||
await this._onSubmit(event); // Submit any unsaved changes
|
||||
const li = a.closest(".damage-part");
|
||||
const damage = duplicate(this.item.data.data.damage);
|
||||
damage.parts.splice(Number(li.dataset.damagePart), 1);
|
||||
return this.item.update({"data.damage.parts": damage.parts});
|
||||
return this.item.update({ "data.damage.parts": damage.parts });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -341,19 +328,19 @@ export default class ItemSheet5e extends ItemSheet {
|
|||
name: a.dataset.target,
|
||||
title: label.innerText,
|
||||
choices: Object.entries(CONFIG.SW5E.skills).reduce((obj, e) => {
|
||||
if ( choices.includes(e[0] ) ) obj[e[0]] = e[1];
|
||||
if (choices.includes(e[0])) obj[e[0]] = e[1];
|
||||
return obj;
|
||||
}, {}),
|
||||
minimum: skills.number,
|
||||
maximum: skills.number
|
||||
}).render(true)
|
||||
}).render(true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
async _onSubmit(...args) {
|
||||
if ( this._tabs[0].active === "details" ) this.position.height = "auto";
|
||||
if (this._tabs[0].active === "details") this.position.height = "auto";
|
||||
await super._onSubmit(...args);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue