Esprit de la Loi + Automaton
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
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: (event, button, dialog) => {
|
||||
MournbladeInvocationEspritDialog._updateRollData(rollData, button.form.elements, actor, {
|
||||
persuasionComp, hautParlerComp, loiChaosComp
|
||||
})
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user