ripcrypt/module/data/Item/Armour.mjs

191 lines
4.4 KiB
JavaScript

import { CommonItemData } from "./Common.mjs";
import { gameTerms } from "../../gameTerms.mjs";
import { localizer } from "../../utils/Localizer.mjs";
import { Logger } from "../../utils/Logger.mjs";
import { requiredInteger } from "../helpers.mjs";
const { fields } = foundry.data;
const { hasProperty, diffObject, mergeObject } = foundry.utils;
/** Used for Armour and Shields */
export class ArmourData extends CommonItemData {
// MARK: Schema
static defineSchema() {
return {
...super.defineSchema(),
protection: requiredInteger({ min: 0, initial: 1 }),
location: new fields.SetField(
new fields.StringField({
blank: false,
trim: true,
nullable: false,
options: Object.values(gameTerms.Anatomy),
}),
{
nullable: false,
required: true,
},
),
equipped: new fields.BooleanField({
initial: false,
required: true,
nullable: false,
}),
weight: new fields.StringField({
blank: false,
nullable: true,
initial: null,
options: Object.values(gameTerms.WeightRatings),
}),
};
};
// MARK: Base Data
prepareBaseData() {
super.prepareBaseData();
};
// MARK: Derived Data
prepareDerivedData() {
super.prepareDerivedData();
};
// #region Lifecycle
async _preUpdate(changes, options, user) {
// return false
if (options.force && game.settings.get(`ripcrypt`, `devMode`)) { return };
// Ensure changes is a diffed object
const diff = diffObject(this.parent._source, changes);
let valid = await super._preUpdate(changes, options, user);
if (hasProperty(diff, `system.equipped`) && !this._canEquip()) {
ui.notifications.error(
localizer(
`RipCrypt.notifs.error.cannot-equip`,
{ itemType: `@TYPES.Item.${this.parent.type}` },
),
{ console: false },
);
// Don't stop the update, but don't allow changing the equipped status
mergeObject(changes, {
"system.equipped": false,
});
// Set a flag so that we can tell the sheet that it needs to rerender
this.forceRerender = true;
};
return valid;
};
/** Used to tell the preUpdate logic whether or not to prevent the */
_canEquip() {
const parent = this.parent;
if (!parent.isEmbedded || !(parent.parent instanceof Actor)) {
Logger.error(`Unable to equip item when it's not embedded`);
return false;
};
if (this.location.size === 0) {
Logger.error(`Unable to equip an item without any locations`);
return false;
};
const slots = parent.parent.system.equippedArmour ?? {};
Logger.debug(`slots`, slots);
for (const locationTag of this.location) {
if (slots[locationTag.toLowerCase()] != null) {
Logger.error(`Unable to equip multiple items in the same slot`);
return false;
};
};
return true;
};
// #endregion
// #region Getters
get locationString() {
return [...this.location].join(`, `);
};
// #endregion
// #region Sheet Data
getFormFields(_ctx) {
const fields = [
{
id: `quantity`,
type: `integer`,
label: `RipCrypt.common.quantity`,
path: `system.quantity`,
value: this.quantity,
min: 0,
},
{
id: `access`,
type: `dropdown`,
label: `RipCrypt.common.access`,
path: `system.access`,
value: this.access,
limited: false,
options: [
{
label: `RipCrypt.common.empty`,
value: ``,
},
...gameTerms.Access.map(opt => ({
label: `RipCrypt.common.accessLevels.${opt}`,
value: opt,
})),
],
},
{
id: `weight`,
type: `dropdown`,
label: `RipCrypt.common.weightRating`,
path: `system.weight`,
value: this.weight,
options: [
{
label: `RipCrypt.common.empty`,
value: null,
},
...Object.values(gameTerms.WeightRatings).map(opt => ({
label: `RipCrypt.common.weightRatings.${opt}`,
value: opt,
})),
],
},
{
id: `location`,
type: `string-set`,
label: `RipCrypt.common.location`,
placeholder: `RipCrypt.Apps.location-placeholder`,
path: `system.location`,
value: this.locationString,
},
{
id: `protection`,
type: `integer`,
label: `RipCrypt.common.protection`,
value: this.protection,
path: `system.protection`,
min: 0,
},
];
if (this.parent.isEmbedded) {
fields.push({
id: `equipped`,
type: `boolean`,
label: `RipCrypt.common.equipped`,
value: this.equipped,
path: `system.equipped`,
});
};
return fields;
};
// #endregion
};