Files
vermine2047/module/applications/sheets/base-item-sheet.mjs
T
uberwald 70a97796a3 feat: gestion de la Fiabilité du matériel (test de Fiabilité + réparations)
- module/system/reliability.mjs : VermineReliability
  - Test de Fiabilité : jet Xd10 (Mineurs 1D / Graves 3D / Critiques 5D),
    chaque dé >= Fiabilité inflige 1 Dommage ; réduit Fiabilité et dommages
    cumulés (panne/état/effet) ; destruction à 0
  - Traits appliqués : Coque (absorbe n puis se perd), Cassant (+1 perte),
    Étanche (Dommages d'immersion ignorés si Fiabilité au max)
  - Réparations : classique (Précision + Artisanat/Mécanique/Technologie/
    Armurerie vs Fiabilité d'origine + Handicap de panne, +1 Fiabilité/Réussite)
    et de fortune (Précision + Bricolage, panne réparée sans gain de Fiabilité)
- ReliabilityDialog (test/réparation) + cartes de chat dédiées
- Boutons Test de Fiabilité / Réparer sur les fiches d'items (weapon/defense/item)
- i18n fr/en + styles des cartes et boutons
2026-08-07 08:57:35 +02:00

138 lines
5.3 KiB
JavaScript

const { HandlebarsApplicationMixin } = foundry.applications.api
/**
* Fiche de base pour tous les items Vermine 2047 (ApplicationV2).
*/
export class VermineBaseItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
// ── Mode édition ────────────────────────────────────────────────────
static SHEET_MODES = { EDIT: 0, PLAY: 1 }
_sheetMode = this.constructor.SHEET_MODES.PLAY
get isPlayMode() { return this._sheetMode === this.constructor.SHEET_MODES.PLAY }
get isEditMode() { return this._sheetMode === this.constructor.SHEET_MODES.EDIT }
// ── Options par défaut ──────────────────────────────────────────────
static DEFAULT_OPTIONS = {
classes: ["vermine2047", "item"],
position: { width: 560, height: "auto" },
form: { submitOnChange: true },
window: { resizable: true },
actions: {
editImage: VermineBaseItemSheet.#onEditImage,
toggleSheet: VermineBaseItemSheet.#onToggleSheet,
clickDamage: VermineBaseItemSheet.#onClickDamage,
openTraits: VermineBaseItemSheet.#onOpenTraits,
reliabilityTest: VermineBaseItemSheet.#onReliabilityTest,
reliabilityRepair: VermineBaseItemSheet.#onReliabilityRepair
}
}
// ── Drag & Drop ─────────────────────────────────────────────────────
#dragDrop
constructor(options = {}) {
super(options)
this.#dragDrop = this.#createDragDropHandlers()
}
#createDragDropHandlers() {
if (!this.options.dragDrop) return []
return this.options.dragDrop.map(d => {
d.permissions = {
dragstart: this._canDragStart.bind(this),
drop: this._canDragDrop.bind(this)
}
d.callbacks = {
dragover: this._onDragOver.bind(this),
drop: this._onDrop.bind(this)
}
return new foundry.applications.ux.DragDrop.implementation(d)
})
}
_canDragStart() { return this.isEditable }
_canDragDrop() { return this.isEditable }
// ── Contexte commun ─────────────────────────────────────────────────
async _prepareContext() {
return {
fields: this.document.schema.fields,
systemFields: this.document.system.schema.fields,
item: this.document,
system: this.document.system,
source: this.document.toObject(),
config: CONFIG.VERMINE,
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true }),
isEditMode: this.isEditMode,
isPlayMode: this.isPlayMode,
isEditable: this.isEditable
}
}
// ── Rendu ───────────────────────────────────────────────────────────
_onRender(context, options) {
super._onRender(context, options);
this.#dragDrop.forEach(d => d.bind(this.element))
}
// ── Sauvegarde ───────────────────────────────────────────────────────
/** @override */
_prepareSubmitData(event, form, formData, updateData) {
return super._prepareSubmitData(event, form, formData, updateData)
}
// ── Actions ─────────────────────────────────────────────────────────
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 ?? "img"
const current = foundry.utils.getProperty(this.document, attr)
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 #onClickDamage(event, target) {
// Les radios de dégâts sont 1-based dans le template (value="{{@index}}" avec index 1..max)
// mais le stockage est 0-based. On soustrait 1 avant de sauvegarder.
const prop = target.name
const value = parseInt(target.value) - 1
this.document.update({ [prop]: value })
}
static async #onOpenTraits(event, target) {
const { TraitSelector } = await import("../../system/applications.mjs")
new TraitSelector(this.document).render(true)
}
static async #onReliabilityTest() {
const { ReliabilityDialog } = await import("../../system/dialogs/reliabilityDialog.mjs")
const dialog = new ReliabilityDialog({ item: this.document, mode: "test" })
await dialog.render(true)
}
static async #onReliabilityRepair() {
const { ReliabilityDialog } = await import("../../system/dialogs/reliabilityDialog.mjs")
const dialog = new ReliabilityDialog({ item: this.document, mode: "repair" })
await dialog.render(true)
}
}