Files
DeltaGreen/module/item/item-sheet.js
T

192 lines
5.5 KiB
JavaScript

import {
DGPercentileRoll,
DGLethalityRoll,
DGDamageRoll,
DGSanityDamageRoll,
} from "../roll/roll.js";
/**
* Extend the basic ItemSheet with some very simple modifications
* @extends {ItemSheet}
*/
export default class DeltaGreenItemSheet extends foundry.appv1.sheets
.ItemSheet {
/** @override */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["deltagreen", "sheet", "item"],
width: 520,
height: 600,
tabs: [
{
navSelector: ".sheet-tabs",
contentSelector: ".sheet-body",
initial: "attributes",
},
],
});
}
/** @override */
get template() {
const path = "systems/deltagreen/templates/item";
// unique item sheet by type, like `weapon-sheet.html`.
return `${path}/item-${this.item.type}-sheet.html`;
}
/* -------------------------------------------- */
/** @override */
async getData() {
const data = super.getData();
data.enrichedDescription =
await foundry.applications.ux.TextEditor.implementation.enrichHTML(
this.object.system.description,
{ async: true },
);
if (data.item.type === "tome" || data.item.type === "ritual") {
data.enrichedHandlerNotes =
await foundry.applications.ux.TextEditor.implementation.enrichHTML(
this.object.system.handlerNotes,
{ async: true },
);
}
return data;
}
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - 192;
sheetBody.css("height", bodyHeight);
return position;
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
// Everything below here is only needed if the sheet is editable
// eslint-disable-next-line no-useless-return
if (!this.options.editable) return;
// Rollable abilities - bind to everything with the 'Rollable' class
html.find(".rollable").click(this._onRoll.bind(this));
html.find(".rollable").contextmenu(this._onRoll.bind(this)); // this is for right-click, which triggers the roll modifier dialogue for most rolls
// toggle whether information is shown to a player for a tome or not
html.find(".tome-show-hide-info").click((event) => {
event.preventDefault();
this.item.system.revealed = !this.item.system.revealed;
this.item.update({ "system.revealed": this.item.system.revealed });
});
}
/**
* Handle clickable rolls.
*
* @param {Event} event The originating click event
* @async
* @private
*/
async _onRoll(event) {
event.preventDefault();
const element = event.currentTarget;
const { dataset } = element;
if (event && event.which === 2) {
// probably don't want rolls to trigger from a middle mouse click so just kill it here
return;
}
// const item = this.actor.items.get(dataset.iid);
const rollOptions = {
rollType: dataset.rolltype,
key: dataset.key,
// actor: this,
specialTrainingName: dataset?.name || null, // Only applies to Special Training Rolls
item: this.item,
};
// Create a default 1d100 roll just in case.
let roll = new Roll("1d100", {});
switch (dataset.rolltype) {
case "stat":
case "skill":
case "sanity":
case "special-training":
case "weapon":
roll = new DGPercentileRoll("1D100", {}, rollOptions);
break;
case "lethality":
roll = new DGLethalityRoll("1D100", {}, rollOptions);
break;
case "damage": {
let diceFormula = this.item.system.damage;
const { skill } = this.item.system;
if (
(this.actor.type === "agent" || this.actor.type === "npc") &&
(skill === "unarmed_combat" || skill === "melee_weapons")
) {
diceFormula +=
this.actor.system.statistics.str.meleeDamageBonusFormula;
}
roll = new DGDamageRoll(diceFormula, {}, rollOptions);
break;
}
case "sanity-damage": {
const { successLoss, failedLoss } = this.item.system.sanity;
const combinedFormula = `{${successLoss}, ${failedLoss}}`;
roll = new DGSanityDamageRoll(combinedFormula, {}, rollOptions);
break;
}
default:
break;
}
this.processRoll(event, roll, rollOptions);
}
/**
* Show a dialog for the roll and then send to chat.
* Broke this logic out from `_onRoll()` so that other files can call it,
* namely the macro logic.
*
* TODO: Move this logic to the roll.js.
*
* @param {Event} event The originating click event
* @param {Event} roll The roll to show a dialog for and then send to chat.
* @async
*/
async processRoll(event, roll) {
// Open dialog if user requests it (no dialog for Sanity Damage rolls)
if (
(event.shiftKey || event.which === 3) &&
!(roll instanceof DGSanityDamageRoll)
) {
const dialogData = await roll.showDialog();
if (!dialogData) return;
if (dialogData.newFormula) {
roll = new DGDamageRoll(dialogData.newFormula, {}, roll.options);
}
roll.modifier += dialogData.targetModifier;
roll.options.rollMode = dialogData.rollMode;
}
// Evaluate the roll.
await roll.evaluate();
// Send the roll to chat.
roll.toChat();
}
}