diff --git a/src/hud/shared/base.ts b/src/hud/shared/base.ts index e342e42..b86f504 100644 --- a/src/hud/shared/base.ts +++ b/src/hud/shared/base.ts @@ -1,4 +1,4 @@ -import { R, canObserveActor, getSetting, htmlClosest, signedInteger } from "foundry-pf2e"; +import { R, canObserveActor, getSetting, signedInteger } from "foundry-pf2e"; const IWR_DATA = [ { type: "immunities", icon: "fa-solid fa-ankh", label: "PF2E.ImmunitiesLabel" }, @@ -120,32 +120,6 @@ function getStatistics(actor: ActorPF2e) { ); } -function getItemFromElement( - el: HTMLElement, - actor: ActorPF2e -): T | null | Promise { - const element = htmlClosest(el, ".item"); - if (!element) return null; - - const { parentId, itemId, itemUuid, itemType, actionIndex, entryId } = element.dataset; - - const item = parentId - ? actor.inventory.get(parentId, { strict: true }).subitems.get(itemId, { strict: true }) - : itemUuid - ? fromUuid(itemUuid) - : entryId - ? actor.spellcasting?.collections - .get(entryId, { strict: true }) - .get(itemId, { strict: true }) ?? null - : itemType === "condition" - ? actor.conditions.get(itemId, { strict: true }) - : actionIndex - ? actor.system.actions?.[Number(actionIndex)].item ?? null - : actor.items.get(itemId ?? "") ?? null; - - return item as T | null | Promise; -} - function userCanObserveActor(actor: ActorPF2e) { return ( canObserveActor(actor, true) || @@ -200,13 +174,5 @@ type HealthData = { max: number; }; -export { - IWR_DATA, - getHealth, - getItemFromElement, - getSpeeds, - getStatistics, - getStatsHeader, - userCanObserveActor, -}; +export { IWR_DATA, getHealth, getSpeeds, getStatistics, getStatsHeader, userCanObserveActor }; export type { HealthData, StatsHeader, StatsSpeed, StatsSpeeds, StatsStatistic }; diff --git a/src/hud/sidebar/actions.ts b/src/hud/sidebar/actions.ts index c0500ee..bfaf85d 100644 --- a/src/hud/sidebar/actions.ts +++ b/src/hud/sidebar/actions.ts @@ -23,7 +23,6 @@ import { } from "foundry-pf2e"; import { getNpcStrikeImage } from "../../utils/npc-attacks"; import { PF2eHudTextPopup } from "../popup/text"; -import { getItemFromElement } from "../shared/base"; import { PF2eHudSidebar, SidebarContext, SidebarName, SidebarRenderOptions } from "./base"; import { EXTRAS_ACTIONS_UUIDS } from "./extras"; import { SKILL_ACTIONS_UUIDS } from "./skills"; @@ -261,41 +260,38 @@ class PF2eHudSidebarActions extends PF2eHudSidebar { } } - _activateListeners(html: HTMLElement) { - const actor = this.actor; + getBlastFromElement(el: HTMLElement) { const { elementTraits, damageTypes } = CONFIG.PF2E; + const melee = el.dataset.melee === "true"; + const blast = new game.pf2e.ElementalBlast(this.actor as CharacterPF2e); + const itemRow = htmlClosest(el, ".item")!; + const element = itemRow.dataset.element; + const damageType = el.dataset.value || itemRow.dataset.damageType; + + if (!objectHasKey(elementTraits, element)) { + throw ErrorPF2e("Unexpected error retrieve element"); + } + if (!objectHasKey(damageTypes, damageType)) { + throw ErrorPF2e("Unexpected error retrieving damage type"); + } - const getBlast = (button: HTMLElement, itemRow: HTMLElement) => { - const melee = button.dataset.melee === "true"; - const blast = new game.pf2e.ElementalBlast(actor as CharacterPF2e); - const element = itemRow.dataset.element; - const damageType = button.dataset.value || itemRow.dataset.damageType; - - if (!objectHasKey(elementTraits, element)) { - throw ErrorPF2e("Unexpected error retrieve element"); - } - if (!objectHasKey(damageTypes, damageType)) { - throw ErrorPF2e("Unexpected error retrieving damage type"); - } + return [blast, { element, damageType, melee }] as const; + } - return [blast, { element, damageType, melee }] as const; - }; + getStrikeFromElement(el: HTMLElement, readyOnly = false): T | null { + const actionIndex = Number(htmlClosest(el, ".item")?.dataset.actionIndex ?? "NaN"); + const strike = this.actor.system.actions?.at(actionIndex) ?? null; + return getStrikeVariant(strike, el, readyOnly); + } - const getStrike = ( - button: HTMLElement, - readyOnly = false - ): T | null => { - const actionIndex = Number(htmlClosest(button, ".item")?.dataset.actionIndex ?? "NaN"); - const strike = this.actor.system.actions?.at(actionIndex) ?? null; - return getStrikeVariant(strike, button, readyOnly); - }; + _activateListeners(html: HTMLElement) { + const actor = this.actor; const getUUID = (button: HTMLElement) => { return elementDataset(htmlClosest(button, ".item")!).uuid; }; addListenerAll(html, "[data-action]", async (event, button) => { - const itemRow = htmlClosest(button, ".item")!; const action = button.dataset.action as Action; switch (action) { @@ -311,7 +307,7 @@ class PF2eHudSidebarActions extends PF2eHudSidebar { } case "toggle-trait": { - const item = await getItemFromElement(button, actor); + const item = await this.getItemFromElement(button); if (!isOwnedItem(item) || !item.isOfType("action", "feat")) return; const trait = button.dataset.trait as "mindshift"; @@ -336,20 +332,20 @@ class PF2eHudSidebarActions extends PF2eHudSidebar { } case "blast-attack": { - const [blast, data] = getBlast(button, itemRow); + const [blast, data] = this.getBlastFromElement(button); const mapIncreases = Math.clamp(Number(button.dataset.mapIncreases), 0, 2); return blast.attack({ ...data, mapIncreases, event }); } case "blast-damage": { - const [blast, data] = getBlast(button, itemRow); + const [blast, data] = this.getBlastFromElement(button); const outcome = button.dataset.outcome === "success" ? "success" : "criticalSuccess"; return blast.damage({ ...data, outcome, event }); } case "blast-set-damage-type": { - const [blast, data] = getBlast(button, itemRow); + const [blast, data] = this.getBlastFromElement(button); return blast.setDamageType(data); } @@ -358,14 +354,14 @@ class PF2eHudSidebarActions extends PF2eHudSidebar { ? button.dataset.altUsage : null; - const strike = getStrike(button, true); + const strike = this.getStrikeFromElement(button, true); const variantIndex = Number(button.dataset.variantIndex); return strike?.variants[variantIndex]?.roll({ event, altUsage }); } case "strike-damage": case "strike-critical": { - const strike = getStrike(button); + const strike = this.getStrikeFromElement(button); const method = button.dataset.action === "strike-damage" ? "damage" : "critical"; return strike?.[method]?.({ event }); @@ -373,14 +369,14 @@ class PF2eHudSidebarActions extends PF2eHudSidebar { case "auxiliary-action": { const auxiliaryActionIndex = Number(button.dataset.auxiliaryActionIndex ?? NaN); - const strike = getStrike(button); + const strike = this.getStrikeFromElement(button); const selection = htmlQuery(button, "select")?.value ?? null; strike?.auxiliaryActions?.at(auxiliaryActionIndex)?.execute({ selection }); break; } case "toggle-weapon-trait": { - const weapon = getStrike(button)?.item; + const weapon = this.getStrikeFromElement(button)?.item; const trait = button.dataset.trait; const errorMessage = "Unexpected failure while toggling weapon trait"; @@ -464,12 +460,12 @@ class PF2eHudSidebarActions extends PF2eHudSidebar { } case "use-action": { - const item = await getItemFromElement(button, actor); + const item = await this.getItemFromElement(button); return item?.isOfType("feat", "action") && useAction(event, item); } case "reset-action": { - const item = await getItemFromElement(button, actor); + const item = await this.getItemFromElement(button); const frequency = item?.frequency; if (!item || !frequency?.max) return; return item.update({ "system.frequency.value": frequency.max }); @@ -483,7 +479,7 @@ class PF2eHudSidebarActions extends PF2eHudSidebar { "change", (event, ammoSelect: HTMLSelectElement) => { event.stopPropagation(); - const action = getStrike(ammoSelect); + const action = this.getStrikeFromElement(ammoSelect); const weapon = action?.item; const ammo = this.actor.items.get(ammoSelect.value); weapon?.update({ system: { selectedAmmoId: ammo?.id ?? null } }); diff --git a/src/hud/sidebar/base.ts b/src/hud/sidebar/base.ts index 5d21800..52277a4 100644 --- a/src/hud/sidebar/base.ts +++ b/src/hud/sidebar/base.ts @@ -20,7 +20,6 @@ import { PF2eHudBaseActor } from "../base/actor"; import { IPF2eHudAdvanced } from "../base/advanced"; import { PF2eHudItemPopup } from "../popup/item"; import { addDragoverListener } from "../shared/advanced"; -import { getItemFromElement } from "../shared/base"; import { addEnterKeyListeners } from "../shared/listeners"; const SIDEBARS = [ @@ -340,6 +339,30 @@ abstract class PF2eHudSidebar extends foundry.applications.api return super.close(options); } + getItemFromElement(el: HTMLElement): T | null | Promise { + const actor = this.actor; + const element = htmlClosest(el, ".item"); + if (!element) return null; + + const { parentId, itemId, itemUuid, itemType, actionIndex, entryId } = element.dataset; + + const item = parentId + ? actor.inventory.get(parentId, { strict: true }).subitems.get(itemId, { strict: true }) + : itemUuid + ? fromUuid(itemUuid) + : entryId + ? actor.spellcasting?.collections + .get(entryId, { strict: true }) + .get(itemId, { strict: true }) ?? null + : itemType === "condition" + ? actor.conditions.get(itemId, { strict: true }) + : actionIndex + ? actor.system.actions?.[Number(actionIndex)].item ?? null + : actor.items.get(itemId ?? "") ?? null; + + return item as T | null | Promise; + } + getMaxHeight(inner?: boolean) { const { limits } = this.parentHUD.anchor; const maxHeightRatio = PF2eHudSidebar.getSetting("maxHeight") / 100; @@ -370,7 +393,7 @@ abstract class PF2eHudSidebar extends foundry.applications.api const { label, domain, option } = el.dataset; const item = (() => { - const item = getItemFromElement(el, this.actor); + const item = this.getItemFromElement(el); return item instanceof Item ? item : null; })(); @@ -407,7 +430,7 @@ abstract class PF2eHudSidebar extends foundry.applications.api } addListenerAll(html, "[data-action='send-to-chat']", async (event, el) => { - const item = await getItemFromElement(el, actor); + const item = await this.getItemFromElement(el); if (!item) return; if (!isOwnedItem(item)) { @@ -431,7 +454,7 @@ abstract class PF2eHudSidebar extends foundry.applications.api addListenerAll(html, "[data-action='item-description']", async (event, el) => { const actor = this.actor; - const item = await getItemFromElement(el, actor); + const item = await this.getItemFromElement(el); if (!item) return; new PF2eHudItemPopup({ actor, item, event }).render(true); }); diff --git a/src/hud/sidebar/items.ts b/src/hud/sidebar/items.ts index 91ad5dd..0d34530 100644 --- a/src/hud/sidebar/items.ts +++ b/src/hud/sidebar/items.ts @@ -10,7 +10,6 @@ import { htmlClosest, tupleHasValue, } from "foundry-pf2e"; -import { getItemFromElement } from "../shared/base"; import { PF2eHudSidebar, SidebarContext, SidebarName, SidebarRenderOptions } from "./base"; class PF2eHudSidebarItems extends PF2eHudSidebar { @@ -81,7 +80,7 @@ class PF2eHudSidebarItems extends PF2eHudSidebar { addListenerAll(html, "[data-action]:not(disabled)", async (event, el) => { const action = el.dataset.action as ItemsActionEvent; - const item = await getItemFromElement(el, actor); + const item = await this.getItemFromElement(el); if (!item?.isOfType("physical")) return; switch (action) { diff --git a/src/hud/sidebar/spells.ts b/src/hud/sidebar/spells.ts index 6016d19..6090553 100644 --- a/src/hud/sidebar/spells.ts +++ b/src/hud/sidebar/spells.ts @@ -53,6 +53,21 @@ class PF2eHudSidebarSpells extends PF2eHudSidebar { return target.dataset; } + getSpellFromElement(target: HTMLElement) { + const spellRow = htmlClosest(target, "[data-item-id]"); + const { itemId, entryId, slotId } = spellRow?.dataset ?? {}; + const collection = this.actor.spellcasting.collections.get(entryId, { + strict: true, + }); + + return { + slotId, + collection, + castRank: spellRow?.dataset.castRank, + spell: collection.get(itemId, { strict: true }), + }; + } + _activateListeners(html: HTMLElement) { const actor = this.actor; const isCharacter = actor.isOfType("character"); @@ -91,7 +106,7 @@ class PF2eHudSidebarSpells extends PF2eHudSidebar { switch (action) { case "cast-spell": { - const { spell, castRank, collection, slotId } = getSpellFromElement(actor, el); + const { spell, castRank, collection, slotId } = this.getSpellFromElement(el); const maybeCastRank = Number(castRank) || NaN; if (!Number.isInteger(maybeCastRank) || !maybeCastRank.between(1, 10)) return; @@ -125,7 +140,7 @@ class PF2eHudSidebarSpells extends PF2eHudSidebar { } case "toggle-signature": { - const { spell } = getSpellFromElement(actor, el); + const { spell } = this.getSpellFromElement(el); return spell.update({ "system.location.signature": !spell.system.location.signature, }); @@ -135,21 +150,6 @@ class PF2eHudSidebarSpells extends PF2eHudSidebar { } } -function getSpellFromElement(actor: CreaturePF2e, target: HTMLElement) { - const spellRow = htmlClosest(target, "[data-item-id]"); - const { itemId, entryId, slotId } = spellRow?.dataset ?? {}; - const collection = actor.spellcasting.collections.get(entryId, { - strict: true, - }); - - return { - slotId, - collection, - castRank: spellRow?.dataset.castRank, - spell: collection.get(itemId, { strict: true }), - }; -} - type SpellDrawData = { parentId: string; annotation: NonNullable;