import { MournbladeUtility } from "../mournblade-utility.js" export default class MournbladeInvocationEspritDialog { static _normalize(str) { return (str ?? "") .toLowerCase() .replace(/œ/g, "oe").replace(/æ/g, "ae") .normalize("NFD").replace(/[\u0300-\u036f]/g, "") .replace(/[^a-z0-9]+/g, " ").trim() } static _findCompetence(actor, ...keywords) { const normKeys = keywords.map(k => MournbladeInvocationEspritDialog._normalize(k)) return actor.items.find(item => { if (item.type !== "competence") return false const norm = MournbladeInvocationEspritDialog._normalize(item.name) return normKeys.every(k => norm.includes(k)) }) ?? null } /** Seuil and soul cost per puissance */ static SEUILS = { mineur: 15, median: 20, majeur: 25 } static async create(actor, rollData) { const ameDisponible = Math.max(0, actor.system.ame.currentmax - actor.system.ame.value) const persuasionComp = MournbladeInvocationEspritDialog._findCompetence(actor, "persuasion") const hautParlerComp = MournbladeInvocationEspritDialog._findCompetence(actor, "haut", "parler") const loiChaosComp = MournbladeInvocationEspritDialog._findCompetence(actor, "loi", "chaos") const isLoyal = actor.system.balance.loi > actor.system.balance.chaos const hasRuneLoi = actor.items.some(i => i.type === "rune" && MournbladeInvocationEspritDialog._normalize(i.name).includes("loi") ) const prerequisOk = isLoyal && hasRuneLoi const automatonTypes = { combat: "Combat", voyage: "Voyage", perception: "Perception", restauration:"Restauration", reparateur: "Réparateur", } const context = { ...rollData, img: actor.img, name: actor.name, ameDisponible, treValeur: actor.system.attributs?.tre?.value ?? 0, persuasionNiveau: persuasionComp?.system?.niveau ?? null, hautParlerNiveau: hautParlerComp?.system?.niveau ?? null, loiChaosNiveau: loiChaosComp?.system?.niveau ?? null, isLoyal, hasRuneLoi, prerequisOk, automatonTypes, seuils: MournbladeInvocationEspritDialog.SEUILS, modOptions: Array.from({ length: 21 }, (_, i) => i - 10), } const content = await foundry.applications.handlebars.renderTemplate( "systems/fvtt-mournblade/templates/dialog-invocation-esprit.hbs", context ) Hooks.once("renderDialogV2", (_app, html) => { const form = html.querySelector ? html : html[0] MournbladeInvocationEspritDialog._attachListeners(form, ameDisponible, prerequisOk) }) return foundry.applications.api.DialogV2.wait({ window: { title: "Invoquer un Esprit de la Loi", icon: "fa-solid fa-star" }, classes: ["mournblade-roll-dialog"], position: { width: 520 }, modal: false, content, buttons: [ { action: "invoquer", label: "Invoquer", icon: "fa-solid fa-star", default: true, callback: async (event, button, dialog) => { MournbladeInvocationEspritDialog._updateRollData(rollData, button.form.elements, actor, { persuasionComp, hautParlerComp, loiChaosComp }) await MournbladeUtility.rollInvocationEsprit(rollData) } }, ], rejectClose: false, }) } static _attachListeners(html, ameDisponible, prerequisOk = true) { const invoquerBtn = html.querySelector('button[data-action="invoquer"]') if (invoquerBtn) invoquerBtn.disabled = !prerequisOk const puissanceEl = html.querySelector('[name="puissance"]') const seuilEl = html.querySelector('#esprit-seuil-total') const coutEl = html.querySelector('#esprit-cout-ame') const hiddenEl = html.querySelector('#esprit-seuil-hidden') const warnEl = html.querySelector('#esprit-ame-warn') const dureeEl = html.querySelector('#esprit-duree') const DUREE = { mineur: "1 heure", median: "1 jour", majeur: "1 semaine" } const recalculate = () => { const puissance = puissanceEl?.value ?? "mineur" const seuil = MournbladeInvocationEspritDialog.SEUILS[puissance] ?? 15 if (seuilEl) seuilEl.textContent = seuil if (coutEl) coutEl.textContent = seuil if (hiddenEl) hiddenEl.value = seuil if (dureeEl) dureeEl.textContent = DUREE[puissance] ?? "1 heure" if (warnEl) warnEl.style.display = seuil > ameDisponible ? "" : "none" } if (puissanceEl) puissanceEl.addEventListener("change", recalculate) recalculate() } static _updateRollData(rollData, formElements, actor, { persuasionComp }) { const seuil = parseInt(formElements["seuil"]?.value ?? 15) const modificateur = parseInt(formElements["modificateur"]?.value ?? 0) const automatonType = formElements["automatonType"]?.value ?? "combat" const puissance = formElements["puissance"]?.value ?? "mineur" rollData.invocationSeuil = seuil rollData.invocationSoulCost = seuil rollData.difficulte = seuil rollData.modificateur = modificateur rollData.competence = persuasionComp ?? null rollData.automatonType = automatonType rollData.automatonPuissance = puissance } }