244 lines
7.6 KiB
JavaScript
244 lines
7.6 KiB
JavaScript
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,
|
|
transferThread: LesOubliesActorSheet.#onTransferThread,
|
|
},
|
|
}
|
|
|
|
_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)
|
|
}
|
|
|
|
static async #onTransferThread(event, target) {
|
|
const resourceKey = target.dataset.resourceKey
|
|
const direction = target.dataset.direction || "toCompany"
|
|
if (!resourceKey || !this.document?.transferThreadReserve) return
|
|
|
|
const row = target.closest("[data-transfer-row]")
|
|
const amountField = row?.querySelector?.("[data-transfer-amount]")
|
|
const amount = Math.max(Math.trunc(Number(amountField?.value ?? 1)), 0)
|
|
if (amount < 1) {
|
|
ui.notifications.warn("Indiquez une quantité à transférer.")
|
|
return
|
|
}
|
|
|
|
const success = await this.document.transferThreadReserve(resourceKey, amount, direction)
|
|
if (!success) {
|
|
ui.notifications.warn("Transfert impossible avec les réserves actuelles.")
|
|
return
|
|
}
|
|
|
|
this.render()
|
|
}
|
|
}
|