import { AcksActor } from "./entity.js"; import { AcksEntityTweaks } from "../dialog/entity-tweaks.js"; export class AcksActorSheet extends ActorSheet { constructor(...args) { super(...args); } /* -------------------------------------------- */ getData() { const data = super.getData(); data.config = CONFIG.ACKS; // Settings data.config.ascendingAC = game.settings.get("acks", "ascendingAC"); data.config.encumbrance = game.settings.get("acks", "encumbranceOption"); // Prepare owned items this._prepareItems(data); return data; } _createEditor(target, editorOptions, initialContent) { // remove some controls to the editor as the space is lacking if (target == "data.details.description") { editorOptions.toolbar = "styleselect bullist hr table removeFormat save"; } super._createEditor(target, editorOptions, initialContent); } /** * Organize and classify Owned Items for Character sheets * @private */ _prepareItems(data) { // Partition items by category let [items, weapons, armors, abilities, spells] = data.items.reduce( (arr, item) => { // Classify items into types if (item.type === "item") arr[0].push(item); else if (item.type === "weapon") arr[1].push(item); else if (item.type === "armor") arr[2].push(item); else if (item.type === "ability") arr[3].push(item); else if (item.type === "spell") arr[4].push(item); return arr; }, [[], [], [], [], []] ); // Sort spells by level var sortedSpells = {}; var slots = {}; for (var i = 0; i < spells.length; i++) { let lvl = spells[i].data.lvl; if (!sortedSpells[lvl]) sortedSpells[lvl] = []; if (!slots[lvl]) slots[lvl] = 0; slots[lvl] += spells[i].data.memorized; sortedSpells[lvl].push(spells[i]); } data.slots = { used: slots, }; // Assign and return data.owned = { items: items, weapons: weapons, armors: armors, }; data.abilities = abilities; data.spells = sortedSpells; } _onItemSummary(event) { event.preventDefault(); let li = $(event.currentTarget).parents(".item"), item = this.actor.getOwnedItem(li.data("item-id")), description = TextEditor.enrichHTML(item.data.data.description); // Toggle summary if (li.hasClass("expanded")) { let summary = li.parents(".item-entry").children(".item-summary"); summary.slideUp(200, () => summary.remove()); } else { // Add item tags let div = $( `
    ${item.getTags()}
${description}
` ); li.parents(".item-entry").append(div.hide()); div.slideDown(200); } li.toggleClass("expanded"); } async _onSpellChange(event) { event.preventDefault(); const itemId = event.currentTarget.closest(".item").dataset.itemId; const item = this.actor.getOwnedItem(itemId); if (event.target.dataset.field == "cast") { return item.update({ "data.cast": parseInt(event.target.value) }); } else if (event.target.dataset.field == "memorize") { return item.update({ "data.memorized": parseInt(event.target.value), }); } } async _resetSpells(event) { let spells = $(event.currentTarget) .closest(".inventory.spells") .find(".item"); spells.each((_, el) => { let itemId = el.dataset.itemId; const item = this.actor.getOwnedItem(itemId); item.update({ _id: item.id, "data.cast": item.data.data.memorized, }); }); } activateListeners(html) { super.activateListeners(html); // Item summaries html .find(".item .item-name h4") .click((event) => this._onItemSummary(event)); html.find(".item .item-controls .item-show").click(async (ev) => { const li = $(ev.currentTarget).parents(".item"); const item = this.actor.getOwnedItem(li.data("itemId")); item.show(); }); html.find(".saving-throw .attribute-name a").click((ev) => { let actorObject = this.actor; let element = event.currentTarget; let save = element.parentElement.parentElement.dataset.save; actorObject.rollSave(save, { event: event }); }); html.find(".item .item-rollable .item-image").click(async (ev) => { const li = $(ev.currentTarget).parents(".item"); const item = this.actor.getOwnedItem(li.data("itemId")); if (item.type == "weapon") { if (this.actor.data.type === "monster") { item.update({ data: { counter: { value: item.data.data.counter.value - 1 } }, }); } item.rollWeapon({ skipDialog: ev.ctrlKey }); } else if (item.type == "spell") { item.spendSpell({ skipDialog: ev.ctrlKey }); } else { item.rollFormula({ skipDialog: ev.ctrlKey }); } }); html .find(".memorize input") .click((ev) => ev.target.select()) .change(this._onSpellChange.bind(this)); html.find(".attack a").click((ev) => { let actorObject = this.actor; let element = event.currentTarget; let attack = element.parentElement.parentElement.dataset.attack; const rollData = { actor: this.data, roll: {}, }; actorObject.targetAttack(rollData, attack, { type: attack, skipDialog: ev.ctrlKey, }); html.find(".spells .item-reset").click((ev) => { this._resetSpells(ev); }); }); html.find(".hit-dice .attribute-name a").click((ev) => { let actorObject = this.actor; actorObject.rollHitDice({ event: event }); }); html.find(".bhr .attribute-name a").click((ev) => { let actorObject = this.actor; actorObject.rollBHR({ event: event }); }); // Everything below here is only needed if the sheet is editable if (!this.options.editable) return; html .find(".memorize input") .click((ev) => ev.target.select()) .change(this._onSpellChange.bind(this)); html.find(".spells .item-reset").click((ev) => { this._resetSpells(ev); }); } // Override to set resizable initial size async _renderInner(...args) { const html = await super._renderInner(...args); this.form = html[0]; // Resize resizable classes let resizable = html.find(".resizable"); if (resizable.length == 0) { return; } resizable.each((_, el) => { let heightDelta = this.position.height - this.options.height; el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; }); return html; } async _onResize(event) { super._onResize(event); let html = $(this.form); let resizable = html.find(".resizable"); if (resizable.length == 0) { return; } // Resize divs resizable.each((_, el) => { let heightDelta = this.position.height - this.options.height; el.style.height = `${heightDelta + parseInt(el.dataset.baseSize)}px`; }); // Resize editors let editors = html.find(".editor"); editors.each((id, editor) => { let container = editor.closest(".resizable-editor"); if (container) { let heightDelta = this.position.height - this.options.height; editor.style.height = `${ heightDelta + parseInt(container.dataset.editorSize) }px`; } }); } _onConfigureActor(event) { event.preventDefault(); new AcksEntityTweaks(this.actor, { top: this.position.top + 40, left: this.position.left + (this.position.width - 400) / 2, }).render(true); } /** * Extend and override the sheet header buttons * @override */ _getHeaderButtons() { let buttons = super._getHeaderButtons(); // Token Configuration const canConfigure = game.user.isGM || this.actor.owner; if (this.options.editable && canConfigure) { buttons = [ { label: game.i18n.localize("ACKS.dialog.tweaks"), class: "configure-actor", icon: "fas fa-code", onclick: (ev) => this._onConfigureActor(ev), }, ].concat(buttons); } return buttons; } }