Add special abilities to creature sheet
This commit is contained in:
parent
864a65fed2
commit
e36f30a787
12 changed files with 107 additions and 15 deletions
231
src/module/actor/sheets/actor-sheet.ts
Normal file
231
src/module/actor/sheets/actor-sheet.ts
Normal file
|
@ -0,0 +1,231 @@
|
|||
import { DS4Item } from "../../item/item";
|
||||
import { DS4ItemDataType, ItemType } from "../../item/item-data";
|
||||
import { DS4Actor } from "../actor";
|
||||
import { DS4ActorDataType } from "../actor-data";
|
||||
|
||||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
* @extends {ActorSheet}
|
||||
*/
|
||||
export class DS4ActorSheet extends ActorSheet<DS4ActorDataType, DS4Actor, DS4ItemDataType> {
|
||||
/** @override */
|
||||
static get defaultOptions(): FormApplicationOptions {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["ds4", "sheet", "actor"],
|
||||
width: 745,
|
||||
height: 600,
|
||||
});
|
||||
}
|
||||
|
||||
/** @override */
|
||||
get template(): string {
|
||||
const path = "systems/ds4/templates/actor";
|
||||
return `${path}/${this.actor.data.type}-sheet.hbs`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* This method returns the data for the template of the actor sheet.
|
||||
* It explicitly adds the items of the object sorted by type in the
|
||||
* object itemsByType.
|
||||
* @returns the data fed to the template of the actor sheet
|
||||
*/
|
||||
getData(): ActorSheetData<DS4ActorDataType, DS4Actor> {
|
||||
const data = {
|
||||
...super.getData(),
|
||||
// Add the localization config to the data:
|
||||
config: CONFIG.DS4,
|
||||
// Add the items explicitly sorted by type to the data:
|
||||
itemsByType: this.actor.itemTypes,
|
||||
};
|
||||
return data;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
activateListeners(html: JQuery): void {
|
||||
super.activateListeners(html);
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
// Add Inventory Item
|
||||
html.find(".item-create").on("click", this._onItemCreate.bind(this));
|
||||
|
||||
// Update Inventory Item
|
||||
html.find(".item-edit").on("click", (ev) => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
const item = this.actor.getOwnedItem(li.data("itemId"));
|
||||
item.sheet.render(true);
|
||||
});
|
||||
|
||||
// Delete Inventory Item
|
||||
html.find(".item-delete").on("click", (ev) => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
this.actor.deleteOwnedItem(li.data("itemId"));
|
||||
li.slideUp(200, () => this.render(false));
|
||||
});
|
||||
|
||||
html.find(".item-change").on("change", this._onItemChange.bind(this));
|
||||
|
||||
// Rollable abilities.
|
||||
html.find(".rollable").click(this._onRoll.bind(this));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Handle creating a new Owned Item for the actor using initial data defined in the HTML dataset
|
||||
* @param {JQuery.ClickEvent} event The originating click event
|
||||
* @private
|
||||
*/
|
||||
private _onItemCreate(event: JQuery.ClickEvent): Promise<Item> {
|
||||
event.preventDefault();
|
||||
const header = event.currentTarget;
|
||||
// Get the type of item to create.
|
||||
const type = header.dataset.type;
|
||||
// Grab any data associated with this control.
|
||||
const data = duplicate(header.dataset);
|
||||
// Initialize a default name.
|
||||
const name = `New ${type.capitalize()}`;
|
||||
// Prepare the item object.
|
||||
const itemData = {
|
||||
name: name,
|
||||
type: type,
|
||||
data: data,
|
||||
};
|
||||
// Remove the type from the dataset since it's in the itemData.type prop.
|
||||
delete itemData.data.type;
|
||||
|
||||
// Finally, create the item!
|
||||
return this.actor.createOwnedItem(itemData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle changes to properties of an Owned Item from within character sheet.
|
||||
* Can currently properly bind: see getValue().
|
||||
* Assumes the item property is given as the value of the HTML element property 'data-property'.
|
||||
* @param {JQuery.ChangeEvent<HTMLFormElement>} ev The originating change event
|
||||
* @private
|
||||
*/
|
||||
private _onItemChange(ev: JQuery.ChangeEvent<HTMLFormElement>): void {
|
||||
ev.preventDefault();
|
||||
console.log("Current target:", $(ev.currentTarget).get(0)["name"]);
|
||||
const el: HTMLFormElement = $(ev.currentTarget).get(0);
|
||||
const id = $(ev.currentTarget).parents(".item").data("itemId");
|
||||
const item = duplicate(this.actor.getOwnedItem(id)); // getOwnedItem is typed incorrectly, it actually returns a ItemData<DS4ItemDataType>, not an Item
|
||||
const property: string | undefined = $(ev.currentTarget).data("property");
|
||||
|
||||
// Early return:
|
||||
// Disabled => do nothing
|
||||
if (el.disabled || el.getAttribute("disabled")) return;
|
||||
// name not given => raise
|
||||
if (property === undefined) {
|
||||
throw TypeError("HTML element does not provide 'data-property' attribute");
|
||||
}
|
||||
|
||||
// Set new value
|
||||
const newValue = this.getValue(el);
|
||||
setProperty(item, property, newValue);
|
||||
this.actor.updateOwnedItem(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the value of a form element depending on the element's type
|
||||
* The value is parsed to:
|
||||
* - Checkbox: boolean
|
||||
* - Text input: string
|
||||
* - Number: number
|
||||
* @param el the input element to collect the value of
|
||||
*/
|
||||
private getValue(el: HTMLFormElement): boolean | string | number {
|
||||
// One needs to differentiate between e.g. checkboxes (value="on") and select boxes etc.
|
||||
// Checkbox:
|
||||
if (el.type === "checkbox") {
|
||||
const value: boolean = el.checked;
|
||||
return value;
|
||||
}
|
||||
|
||||
// Text input:
|
||||
else if (el.type === "text") {
|
||||
const value: string = el.value;
|
||||
return value;
|
||||
}
|
||||
|
||||
// Numbers:
|
||||
else if (el.type === "number") {
|
||||
const value = Number(el.value.trim());
|
||||
return value;
|
||||
}
|
||||
|
||||
// // Ranges:
|
||||
// else if (el.type === "range") {
|
||||
// const value: string = el.value.trim();
|
||||
// return value;
|
||||
// }
|
||||
|
||||
// // Radio Checkboxes (untested, cf. FormDataExtended.process)
|
||||
// else if (el.type === "radio") {
|
||||
// const chosen: HTMLFormElement = el.find((r: HTMLFormElement) => r["checked"]);
|
||||
// const value: string = chosen ? chosen.value : null;
|
||||
// return value;
|
||||
// }
|
||||
|
||||
// // Multi-Select (untested, cf. FormDataExtended.process)
|
||||
// else if (el.type === "select-multiple") {
|
||||
// const value: Array<string> = [];
|
||||
// el.options.array.forEach((opt: HTMLOptionElement) => {
|
||||
// if (opt.selected) value.push(opt.value);
|
||||
// });
|
||||
// return value;
|
||||
|
||||
// unsupported:
|
||||
else {
|
||||
throw TypeError("Binding of item property to this type of HTML element not supported; given: " + el);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle clickable rolls.
|
||||
* @param {JQuery.ClickEvent} event The originating click event
|
||||
* @private
|
||||
*/
|
||||
private _onRoll(event: JQuery.ClickEvent): void {
|
||||
event.preventDefault();
|
||||
const element = event.currentTarget;
|
||||
const dataset = element.dataset;
|
||||
|
||||
if (dataset.roll) {
|
||||
const roll = new Roll(dataset.roll, this.actor.data.data);
|
||||
const label = dataset.label ? `Rolling ${dataset.label}` : "";
|
||||
roll.roll().toMessage({
|
||||
speaker: ChatMessage.getSpeaker({ actor: this.actor }),
|
||||
flavor: label,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async _onDrop(event: DragEvent): Promise<boolean | unknown> {
|
||||
const data = JSON.parse(event.dataTransfer?.getData("text/plain")) as { type?: string };
|
||||
if (data.type === "Item") {
|
||||
const item = await Item.fromDropData(data as Parameters<typeof DS4Item.fromDropData>[0]);
|
||||
if (item && !this.actor.canOwnItemType(item.data.type as ItemType)) {
|
||||
ui.notifications.warn(
|
||||
game.i18n.format("DS4.WarningActorCannotOwnItem", {
|
||||
actorName: this.actor.name,
|
||||
actorType: this.actor.data.type,
|
||||
itemName: item.name,
|
||||
itemType: item.data.type,
|
||||
}),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
super._onDrop(event);
|
||||
}
|
||||
}
|
11
src/module/actor/sheets/character-sheet.ts
Normal file
11
src/module/actor/sheets/character-sheet.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { DS4ActorSheet } from "./actor-sheet";
|
||||
|
||||
export class DS4CharacterActorSheet extends DS4ActorSheet {
|
||||
/** @override */
|
||||
static get defaultOptions(): FormApplicationOptions {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["ds4", "sheet", "actor", "character"],
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "inventory" }],
|
||||
});
|
||||
}
|
||||
}
|
11
src/module/actor/sheets/creature-sheet.ts
Normal file
11
src/module/actor/sheets/creature-sheet.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { DS4ActorSheet } from "./actor-sheet";
|
||||
|
||||
export class DS4CreatureActorSheet extends DS4ActorSheet {
|
||||
/** @override */
|
||||
static get defaultOptions(): FormApplicationOptions {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["ds4", "sheet", "actor", "creature"],
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "items" }],
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue