Esprit de la Loi + Automaton
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
import { MournbladeUtility } from "../mournblade-utility.js"
|
||||
|
||||
export default class MournbladeEnchantementDialog {
|
||||
|
||||
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 => MournbladeEnchantementDialog._normalize(k))
|
||||
return actor.items.find(item => {
|
||||
if (item.type !== "competence") return false
|
||||
const norm = MournbladeEnchantementDialog._normalize(item.name)
|
||||
return normKeys.every(k => norm.includes(k))
|
||||
}) ?? null
|
||||
}
|
||||
|
||||
static async create(actor, item) {
|
||||
const normalize = MournbladeEnchantementDialog._normalize.bind(MournbladeEnchantementDialog)
|
||||
const findComp = (...kw) => MournbladeEnchantementDialog._findCompetence(actor, ...kw)
|
||||
|
||||
const ameDisponible = Math.max(0, (actor.system.ame.currentmax - actor.system.ame.value))
|
||||
const aspect = actor.system.balance.aspect ?? 0
|
||||
|
||||
// Skill lookups
|
||||
const savoirRunesComp = findComp("rune")
|
||||
const hautParlerComp = findComp("haut", "parler")
|
||||
const artisanatComp = findComp("savoir", "artisanat")
|
||||
const claAttr = actor.system.attributs?.clairvoyance
|
||||
|
||||
// Prerequisite: Rune de la Loi in inventory
|
||||
const hasRuneLoi = actor.items.some(i => {
|
||||
if (i.type !== "rune") return false
|
||||
return normalize(i.name).includes("loi")
|
||||
})
|
||||
|
||||
const savoirRunesNiveau = savoirRunesComp ? (savoirRunesComp.system.niveau ?? 0) : null
|
||||
const hautParlerNiveau = hautParlerComp ? (hautParlerComp.system.niveau ?? 0) : null
|
||||
const artisanatNiveau = artisanatComp ? (artisanatComp.system.niveau ?? 0) : null
|
||||
const claValeur = claAttr ? (claAttr.value ?? 0) : 0
|
||||
|
||||
// Limit: CLA + Savoir:Runes is capped by min(Haut-Parler, Artisanat) if those skills exist
|
||||
const limiteur = (hautParlerNiveau !== null && artisanatNiveau !== null)
|
||||
? Math.min(hautParlerNiveau, artisanatNiveau)
|
||||
: (hautParlerNiveau ?? artisanatNiveau ?? null)
|
||||
|
||||
const context = {
|
||||
actorImg: actor.img,
|
||||
actorName: actor.name,
|
||||
itemImg: item.img,
|
||||
itemName: item.name,
|
||||
itemType: item.type,
|
||||
itemId: item.id,
|
||||
ameDisponible,
|
||||
aspect,
|
||||
hasRuneLoi,
|
||||
savoirRunesNiveau,
|
||||
hautParlerNiveau,
|
||||
artisanatNiveau,
|
||||
claValeur,
|
||||
limiteur,
|
||||
modOptions: Array.from({ length: 21 }, (_, i) => i - 10),
|
||||
enchantementActif: item.system.enchantementLoi?.actif ?? false,
|
||||
enchantementBonus: item.system.enchantementLoi?.bonus ?? 0,
|
||||
enchantementAntiChaos: item.system.enchantementLoi?.antiChaos ?? false,
|
||||
}
|
||||
|
||||
const prerequisOk = hasRuneLoi
|
||||
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
"systems/fvtt-mournblade/templates/dialog-enchantement.hbs",
|
||||
context
|
||||
)
|
||||
|
||||
Hooks.once("renderDialogV2", (_app, html) => {
|
||||
const form = html.querySelector ? html : html[0]
|
||||
MournbladeEnchantementDialog._attachListeners(form, ameDisponible, claValeur, savoirRunesNiveau, limiteur, prerequisOk)
|
||||
})
|
||||
|
||||
return foundry.applications.api.DialogV2.wait({
|
||||
window: { title: `Enchanter : ${item.name}`, icon: "fa-solid fa-star" },
|
||||
classes: ["mournblade-roll-dialog"],
|
||||
position: { width: 520 },
|
||||
modal: false,
|
||||
content,
|
||||
buttons: [
|
||||
{
|
||||
action: "enchanter",
|
||||
label: "Enchanter",
|
||||
icon: "fa-solid fa-star",
|
||||
default: true,
|
||||
callback: (event, button, dialog) => {
|
||||
const elems = button.form.elements
|
||||
const ptsAme = parseInt(elems["ptsAme"]?.value ?? 5) || 5
|
||||
const antiChaos = elems["antiChaos"]?.value === "true"
|
||||
const modificateur = parseInt(elems["modificateur"]?.value ?? 0) || 0
|
||||
MournbladeUtility.rollEnchantement({
|
||||
actor,
|
||||
item,
|
||||
ptsAme,
|
||||
antiChaos,
|
||||
modificateur,
|
||||
savoirRunesComp,
|
||||
hautParlerComp,
|
||||
artisanatComp,
|
||||
claValeur,
|
||||
limiteur,
|
||||
})
|
||||
}
|
||||
},
|
||||
],
|
||||
rejectClose: false,
|
||||
})
|
||||
}
|
||||
|
||||
static _attachListeners(html, ameDisponible, claValeur, savoirRunesNiveau, limiteur, prerequisOk = true) {
|
||||
const enchanterBtn = html.querySelector('button[data-action="enchanter"]')
|
||||
if (enchanterBtn) enchanterBtn.disabled = !prerequisOk
|
||||
|
||||
const diffEl = html.querySelector('#enchant-difficulte')
|
||||
const bonusEl = html.querySelector('#enchant-bonus-preview')
|
||||
const warnAmeEl = html.querySelector('#enchant-ame-warn')
|
||||
const warnLimitEl = html.querySelector('#enchant-limit-warn')
|
||||
const totalEl = html.querySelector('#enchant-total-dice')
|
||||
|
||||
const recalculate = () => {
|
||||
const ptsAme = parseInt(html.querySelector('[name="ptsAme"]')?.value ?? 5) || 0
|
||||
const difficulte = ptsAme
|
||||
const bonus = Math.floor(ptsAme / 5)
|
||||
const savoir = savoirRunesNiveau ?? 0
|
||||
const basePool = claValeur + savoir
|
||||
const effectivePool = limiteur !== null ? Math.min(basePool, limiteur) : basePool
|
||||
|
||||
if (diffEl) diffEl.textContent = difficulte
|
||||
if (bonusEl) bonusEl.textContent = `+${bonus}`
|
||||
if (totalEl) totalEl.textContent = effectivePool
|
||||
|
||||
if (warnAmeEl) warnAmeEl.style.display = ptsAme > ameDisponible ? "" : "none"
|
||||
if (warnLimitEl && limiteur !== null)
|
||||
warnLimitEl.style.display = basePool > limiteur ? "" : "none"
|
||||
}
|
||||
|
||||
const ptsAmeEl = html.querySelector('[name="ptsAme"]')
|
||||
if (ptsAmeEl) {
|
||||
ptsAmeEl.addEventListener('input', recalculate)
|
||||
ptsAmeEl.addEventListener('change', recalculate)
|
||||
}
|
||||
recalculate()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user