313 lines
11 KiB
JavaScript
313 lines
11 KiB
JavaScript
const { HandlebarsApplicationMixin } = foundry.applications.api;
|
|
|
|
import { MournbladeCYD2Utility } from "../../mournblade-cyd2-utility.js";
|
|
|
|
export default class MournbladeCYD2ActorSheetV2 extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
|
|
|
|
static SHEET_MODES = { EDIT: 0, PLAY: 1 };
|
|
|
|
constructor(options = {}) {
|
|
super(options);
|
|
this.#dragDrop = this.#createDragDropHandlers();
|
|
this._sheetMode = this.constructor.SHEET_MODES.PLAY;
|
|
}
|
|
|
|
#dragDrop;
|
|
|
|
/** @override */
|
|
static DEFAULT_OPTIONS = {
|
|
classes: ["fvtt-mournblade-cyd-2-0", "sheet", "actor"],
|
|
position: {
|
|
width: 750,
|
|
height: 820,
|
|
},
|
|
form: {
|
|
submitOnChange: true,
|
|
closeOnSubmit: false,
|
|
},
|
|
window: {
|
|
resizable: true,
|
|
},
|
|
tabs: [
|
|
{
|
|
navSelector: 'nav[data-group="primary"]',
|
|
contentSelector: "section.sheet-body",
|
|
initial: "stats",
|
|
},
|
|
],
|
|
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
|
|
actions: {
|
|
editImage: MournbladeCYD2ActorSheetV2.#onEditImage,
|
|
toggleSheet: MournbladeCYD2ActorSheetV2.#onToggleSheet,
|
|
editItem: MournbladeCYD2ActorSheetV2.#onEditItem,
|
|
deleteItem: MournbladeCYD2ActorSheetV2.#onDeleteItem,
|
|
createItem: MournbladeCYD2ActorSheetV2.#onCreateItem,
|
|
equipItem: MournbladeCYD2ActorSheetV2.#onEquipItem,
|
|
modifyQuantity: MournbladeCYD2ActorSheetV2.#onModifyQuantity,
|
|
modifyAdversite: MournbladeCYD2ActorSheetV2.#onModifyAdversite,
|
|
modifySante: MournbladeCYD2ActorSheetV2.#onModifySante,
|
|
modifyAme: MournbladeCYD2ActorSheetV2.#onModifyAme,
|
|
rollAttribut: MournbladeCYD2ActorSheetV2.#onRollAttribut,
|
|
rollCompetence: MournbladeCYD2ActorSheetV2.#onRollCompetence,
|
|
rollRune: MournbladeCYD2ActorSheetV2.#onRollRune,
|
|
rollArmeOffensif: MournbladeCYD2ActorSheetV2.#onRollArmeOffensif,
|
|
rollArmeSpecial: MournbladeCYD2ActorSheetV2.#onRollArmeSpecial,
|
|
rollArmeDegats: MournbladeCYD2ActorSheetV2.#onRollArmeDegats,
|
|
rollAssommer: MournbladeCYD2ActorSheetV2.#onRollAssommer,
|
|
rollCoupBas: MournbladeCYD2ActorSheetV2.#onRollCoupBas,
|
|
rollImmobiliser: MournbladeCYD2ActorSheetV2.#onRollImmobiliser,
|
|
rollRepousser: MournbladeCYD2ActorSheetV2.#onRollRepousser,
|
|
rollDesengager: MournbladeCYD2ActorSheetV2.#onRollDesengager,
|
|
rollInitiative: MournbladeCYD2ActorSheetV2.#onRollInitiative,
|
|
rollFuir: MournbladeCYD2ActorSheetV2.#onRollFuir,
|
|
},
|
|
};
|
|
|
|
get isPlayMode() {
|
|
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY;
|
|
return this._sheetMode === this.constructor.SHEET_MODES.PLAY;
|
|
}
|
|
|
|
get isEditMode() {
|
|
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY;
|
|
return this._sheetMode === this.constructor.SHEET_MODES.EDIT;
|
|
}
|
|
|
|
tabGroups = { primary: "stats" };
|
|
|
|
/** @override */
|
|
async _prepareContext() {
|
|
const actor = this.document;
|
|
return {
|
|
actor,
|
|
system: actor.system,
|
|
source: actor.toObject(),
|
|
fields: actor.schema.fields,
|
|
systemFields: actor.system.schema.fields,
|
|
isEditable: this.isEditable,
|
|
isEditMode: this.isEditMode,
|
|
isPlayMode: this.isPlayMode,
|
|
isGM: game.user.isGM,
|
|
config: game.system.mournbladecyd2.config,
|
|
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
|
actor.system.biodata?.description || "", { async: true }
|
|
),
|
|
enrichedHabitat: await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
|
actor.system.biodata?.habitat || "", { async: true }
|
|
),
|
|
};
|
|
}
|
|
|
|
/** @override */
|
|
_onRender(context, options) {
|
|
super._onRender(context, options);
|
|
this.#dragDrop.forEach((d) => d.bind(this.element));
|
|
|
|
this.element.querySelectorAll('.edit-item-data').forEach(element => {
|
|
element.addEventListener('change', async (event) => {
|
|
const target = event.currentTarget;
|
|
const itemElement = target.closest('[data-item-id]');
|
|
if (!itemElement) return;
|
|
const itemId = itemElement.dataset.itemId;
|
|
const itemField = target.dataset.itemField;
|
|
const dataType = target.dataset.dtype;
|
|
const value = dataType === "Number" ? Number(target.value) : target.value;
|
|
const item = this.document.items.get(itemId);
|
|
if (item) await item.update({ [itemField]: value });
|
|
});
|
|
});
|
|
|
|
// Tab navigation
|
|
const nav = this.element.querySelector('nav.tabs[data-group]');
|
|
if (nav) {
|
|
const group = nav.dataset.group;
|
|
const activeTab = this.tabGroups[group] || "stats";
|
|
nav.querySelectorAll('[data-tab]').forEach(link => {
|
|
const tab = link.dataset.tab;
|
|
link.classList.toggle('active', tab === activeTab);
|
|
link.addEventListener('click', (event) => {
|
|
event.preventDefault();
|
|
this.tabGroups[group] = tab;
|
|
this.render();
|
|
});
|
|
});
|
|
this.element.querySelectorAll(`[data-group="${group}"][data-tab]`).forEach(content => {
|
|
content.classList.toggle('active', content.dataset.tab === activeTab);
|
|
});
|
|
}
|
|
}
|
|
|
|
#createDragDropHandlers() {
|
|
return this.options.dragDrop.map(d => {
|
|
d.permissions = {
|
|
dragstart: this._canDragStart.bind(this),
|
|
drop: this._canDragDrop.bind(this)
|
|
};
|
|
d.callbacks = {
|
|
dragstart: this._onDragStart.bind(this),
|
|
dragover: this._onDragOver.bind(this),
|
|
drop: this._onDrop.bind(this)
|
|
};
|
|
return new foundry.applications.ux.DragDrop.implementation(d);
|
|
});
|
|
}
|
|
|
|
_canDragStart(selector) { return this.isEditable; }
|
|
_canDragDrop(selector) { return this.isEditable; }
|
|
|
|
_onDragStart(event) {
|
|
const li = event.currentTarget.closest("[data-item-id]");
|
|
if (!li) return;
|
|
const item = this.document.items.get(li.dataset.itemId);
|
|
if (!item) return;
|
|
event.dataTransfer.setData("text/plain", JSON.stringify(item.toDragData()));
|
|
}
|
|
|
|
_onDragOver(event) { event.preventDefault(); }
|
|
|
|
async _onDrop(event) {
|
|
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
|
|
if (data?.type === "Item") return this._onDropItem(event, data);
|
|
if (data?.type === "Actor") return this._onDropActor(event, data);
|
|
}
|
|
|
|
async _onDropItem(event, data) {
|
|
if (!this.document.isOwner) return;
|
|
const item = await Item.fromDropData(data);
|
|
if (!item) return;
|
|
if (this.document.uuid === item.parent?.uuid) return;
|
|
return this.document.createEmbeddedDocuments("Item", [item.toObject()]);
|
|
}
|
|
|
|
async _onDropActor(event, data) {}
|
|
|
|
// #region Actions
|
|
|
|
static async #onEditImage(event) {
|
|
const fp = new FilePicker({
|
|
type: "image",
|
|
current: this.document.img,
|
|
callback: (path) => this.document.update({ img: path })
|
|
});
|
|
fp.browse();
|
|
}
|
|
|
|
static #onToggleSheet(event) {
|
|
this._sheetMode = this.isEditMode
|
|
? this.constructor.SHEET_MODES.PLAY
|
|
: this.constructor.SHEET_MODES.EDIT;
|
|
this.render();
|
|
}
|
|
|
|
static async #onEditItem(event, target) {
|
|
const li = target.closest(".item");
|
|
const item = this.document.items.get(li?.dataset.itemId);
|
|
item?.sheet.render(true);
|
|
}
|
|
|
|
static async #onDeleteItem(event, target) {
|
|
const li = target.closest(".item");
|
|
await MournbladeCYD2Utility.confirmDelete(this, li);
|
|
}
|
|
|
|
static async #onCreateItem(event, target) {
|
|
const itemType = target.dataset.type;
|
|
await this.document.createEmbeddedDocuments("Item", [{ name: `Nouveau ${itemType}`, type: itemType }], { renderSheet: true });
|
|
}
|
|
|
|
static async #onEquipItem(event, target) {
|
|
const li = target.closest(".item");
|
|
const item = this.document.items.get(li?.dataset.itemId);
|
|
if (item) await item.update({ "system.equipped": !item.system.equipped });
|
|
}
|
|
|
|
static async #onModifyQuantity(event, target) {
|
|
const li = target.closest('[data-item-id]');
|
|
const item = this.document.items.get(li?.dataset.itemId);
|
|
const value = Number.parseInt(target.dataset.quantiteValue);
|
|
if (item) {
|
|
const newQty = Math.max(0, (item.system.quantite || 0) + value);
|
|
await item.update({ "system.quantite": newQty });
|
|
}
|
|
}
|
|
|
|
static async #onModifyAdversite(event, target) {
|
|
const li = target.closest('[data-adversite]');
|
|
const adversiteKey = li?.dataset.adversite;
|
|
if (!adversiteKey) return;
|
|
const value = Number.parseInt(target.dataset.adversiteValue);
|
|
const current = this.document.system.adversite[adversiteKey] || 0;
|
|
await this.document.update({ [`system.adversite.${adversiteKey}`]: Math.max(0, current + value) });
|
|
}
|
|
|
|
static async #onModifySante(event, target) {
|
|
const type = target.dataset.type;
|
|
const value = Number.parseInt(target.dataset.value);
|
|
const current = this.document.system.sante[type] || 0;
|
|
await this.document.update({ [`system.sante.${type}`]: Math.max(0, current + value) });
|
|
}
|
|
|
|
static async #onModifyAme(event, target) {
|
|
const value = Number.parseInt(target.dataset.value);
|
|
const current = this.document.system.ame.nbame || 0;
|
|
await this.document.update({ "system.ame.nbame": Math.max(0, current + value) });
|
|
}
|
|
|
|
static async #onRollAttribut(event, target) {
|
|
await this.document.rollAttribut(target.dataset.attrKey);
|
|
}
|
|
|
|
static async #onRollCompetence(event, target) {
|
|
const li = target.closest('[data-item-id]');
|
|
await this.document.rollCompetence(target.dataset.attrKey, li?.dataset.itemId);
|
|
}
|
|
|
|
static async #onRollRune(event, target) {
|
|
const li = target.closest('[data-item-id]');
|
|
await this.document.rollRune(li?.dataset.itemId);
|
|
}
|
|
|
|
static async #onRollArmeOffensif(event, target) {
|
|
const li = target.closest('[data-item-id]');
|
|
await this.document.rollArmeOffensif(target.dataset.armeId ?? li?.dataset.itemId);
|
|
}
|
|
|
|
static async #onRollArmeSpecial(event, target) {
|
|
const li = target.closest('[data-item-id]');
|
|
await this.document.rollArmeSpecial(target.dataset.armeId ?? li?.dataset.itemId);
|
|
}
|
|
|
|
static async #onRollArmeDegats(event, target) {
|
|
const li = target.closest('[data-item-id]');
|
|
await this.document.rollArmeDegats(target.dataset.armeId ?? li?.dataset.itemId);
|
|
}
|
|
|
|
static async #onRollAssommer(event, target) {
|
|
await this.document.rollAssomer();
|
|
}
|
|
|
|
static async #onRollCoupBas(event, target) {
|
|
await this.document.rollCoupBas();
|
|
}
|
|
|
|
static async #onRollImmobiliser(event, target) {
|
|
await this.document.rollImmobiliser();
|
|
}
|
|
|
|
static async #onRollRepousser(event, target) {
|
|
await this.document.rollRepousser();
|
|
}
|
|
|
|
static async #onRollDesengager(event, target) {
|
|
await this.document.rollDesengager();
|
|
}
|
|
|
|
static async #onRollInitiative(event, target) {
|
|
await this.document.rollAttribut("adr", true);
|
|
}
|
|
|
|
static async #onRollFuir(event, target) {
|
|
await this.document.rollFuir();
|
|
}
|
|
}
|