const { HandlebarsApplicationMixin } = foundry.applications.api import { LesOubliesUtility } from "../../les-oublies-utility.js" export default class LesOubliesActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) { static SHEET_MODES = { EDIT: 0, PLAY: 1 } static DEFAULT_OPTIONS = { classes: ["fvtt-les-oublies", "sheet", "actor"], position: { width: 980, height: 860, }, window: { resizable: true, }, form: { submitOnChange: true, closeOnSubmit: false, }, dragDrop: [{ dragSelector: ".item-card", dropSelector: "form" }], actions: { toggleSheet: LesOubliesActorSheet.#onToggleSheet, editImage: LesOubliesActorSheet.#onEditImage, createItem: LesOubliesActorSheet.#onCreateItem, editItem: LesOubliesActorSheet.#onEditItem, deleteItem: LesOubliesActorSheet.#onDeleteItem, openRoll: LesOubliesActorSheet.#onOpenRoll, openConfrontation: LesOubliesActorSheet.#onOpenConfrontation, openInitiative: LesOubliesActorSheet.#onOpenInitiative, rollProfile: LesOubliesActorSheet.#onRollProfile, rollSkill: LesOubliesActorSheet.#onRollSkill, useWeapon: LesOubliesActorSheet.#onUseWeapon, resolveWeaponDamage: LesOubliesActorSheet.#onResolveWeaponDamage, toggleEquipped: LesOubliesActorSheet.#onToggleEquipped, useSpell: LesOubliesActorSheet.#onUseSpell, openCombatPreset: LesOubliesActorSheet.#onOpenCombatPreset, openThreadHarvest: LesOubliesActorSheet.#onOpenThreadHarvest, openLinkedActor: LesOubliesActorSheet.#onOpenLinkedActor, }, } _sheetMode = this.constructor.SHEET_MODES.EDIT get isEditMode() { return this._sheetMode === this.constructor.SHEET_MODES.EDIT } get isPlayMode() { return this._sheetMode === this.constructor.SHEET_MODES.PLAY } async _prepareContext() { const config = CONFIG.LESOUBLIES const enriched = await LesOubliesUtility.prepareEnrichedHtml("Actor", this.document.type, this.document.system) const choiceSets = { profileOptions: config.profiles.map((profile) => ({ value: profile.id, label: profile.label })), personnageSizeOptions: LesOubliesUtility.createRangeChoices(1, 4, config.sizes), creatureSizeOptions: LesOubliesUtility.createRangeChoices(1, 8, config.sizes), } return { actor: this.document, system: this.document.system, source: this.document.toObject(), fields: this.document.schema.fields, systemFields: this.document.system.schema.fields, isEditable: this.isEditable, isEditMode: this.isEditMode, isPlayMode: this.isPlayMode, isGM: game.user.isGM, config, choiceSets, enriched, enrichedDescription: foundry.utils.getProperty(enriched, "biodata.description") ?? foundry.utils.getProperty(enriched, "description") ?? "", } } _onRender(context, options) { super._onRender(context, options) } _canDragStart() { return this.isEditable } _canDragDrop() { return this.isEditable } async _onDrop(event) { const data = TextEditor.getDragEventData(event) if (data.type !== "Item" || !data.uuid) return const item = await fromUuid(data.uuid) if (!item) return return this._onDropItem(item) } async _onDropItem(item) { const itemData = item.toObject() delete itemData._id return this.document.createEmbeddedDocuments("Item", [itemData], { renderSheet: false }) } static #onToggleSheet() { const modes = this.constructor.SHEET_MODES this._sheetMode = this.isEditMode ? modes.PLAY : modes.EDIT this.render() } static async #onEditImage(event, target) { const attr = target.dataset.edit const current = foundry.utils.getProperty(this.document, attr) const FilePicker = foundry.applications.apps.FilePicker.implementation const fp = new FilePicker({ current, type: "image", callback: (path) => this.document.update({ [attr]: path }), top: this.position.top + 40, left: this.position.left + 10, }) return fp.browse() } static async #onCreateItem(event, target) { const type = target.dataset.type if (!type) return const label = game.i18n.localize(`TYPES.Item.${type}`) const itemData = { name: label, type, img: LesOubliesUtility.getDefaultItemImage(type), } if (type === "competence") { itemData.system = { profileKey: CONFIG.LESOUBLIES.profiles[0]?.id ?? "", } } return this.document.createEmbeddedDocuments("Item", [itemData]) } static async #onEditItem(event, target) { const itemId = target.dataset.itemId const item = this.document.items.get(itemId) if (item) item.sheet.render(true) } static async #onDeleteItem(event, target) { const itemId = target.dataset.itemId const item = this.document.items.get(itemId) if (item) await item.delete() } static async #onOpenRoll() { await this.document.openTestRollDialog() } static async #onOpenConfrontation() { await this.document.openConfrontationRollDialog() } static async #onOpenInitiative() { await this.document.openInitiativeRollDialog() } static async #onRollProfile(event, target) { const profileKey = target.dataset.profileKey if (!profileKey) return await this.document.rollProfile(profileKey) } static async #onRollSkill(event, target) { const itemId = target.dataset.itemId if (!itemId) return await this.document.rollCompetence(itemId) } static async #onUseWeapon(event, target) { const itemId = target.dataset.itemId if (!itemId) return await this.document.openAttackRollDialog({ itemId }) } static async #onResolveWeaponDamage(event, target) { const itemId = target.dataset.itemId if (!itemId) return await this.document.openDamageDialog({ itemId }) } static async #onToggleEquipped(event, target) { const itemId = target.dataset.itemId if (!itemId) return const item = this.document.items.get(itemId) if (!item || !("equipped" in (item.system ?? {}))) return await item.update({ "system.equipped": !item.system.equipped }) } static async #onUseSpell(event, target) { const itemId = target.dataset.itemId if (!itemId) return await this.document.openSpellActivationDialog(itemId) } static async #onOpenCombatPreset(event, target) { const actionKey = target.dataset.preset if (!actionKey) return await this.document.openCombatPresetDialog(actionKey) } static async #onOpenThreadHarvest() { await this.document.openThreadHarvestDialog() } static async #onOpenLinkedActor(event, target) { const actorId = target.dataset.actorId if (!actorId) return const actor = game.actors.get(actorId) if (actor) actor.sheet.render(true) } }