96 lines
2.8 KiB
JavaScript
96 lines
2.8 KiB
JavaScript
import { SYSTEM } from "../config/system.mjs"
|
|
|
|
export default class OathHammerMiracleDialog {
|
|
|
|
static async prompt(actor, miracle) {
|
|
const sys = miracle.system
|
|
const actorSys = actor.system
|
|
|
|
const wpRank = actorSys.attributes.willpower.rank
|
|
const magicRank = actorSys.skills.magic.rank
|
|
const basePool = wpRank + magicRank
|
|
|
|
const isRitual = sys.isRitual
|
|
const dv = isRitual ? (sys.difficultyValue || 1) : null
|
|
|
|
const traditionLabel = (() => {
|
|
const key = SYSTEM.DIVINE_TRADITIONS?.[sys.divineTradition]
|
|
return key ? game.i18n.localize(key) : sys.divineTradition
|
|
})()
|
|
|
|
// Miracle count options — DV = miracle number today
|
|
const miracleCountOptions = Array.from({ length: 10 }, (_, i) => ({
|
|
value: i + 1,
|
|
label: `${i + 1}${_ordinal(i + 1)} — DV${i + 1}`,
|
|
selected: i === 0,
|
|
}))
|
|
|
|
const bonusOptions = Array.from({ length: 13 }, (_, i) => {
|
|
const v = i - 6
|
|
return { value: v, label: v > 0 ? `+${v}` : String(v), selected: v === 0 }
|
|
})
|
|
|
|
const rollModes = foundry.utils.duplicate(CONFIG.Dice.rollModes)
|
|
|
|
const context = {
|
|
actorName: actor.name,
|
|
miracleName: miracle.name,
|
|
miracleImg: miracle.img,
|
|
dv,
|
|
traditionLabel,
|
|
isRitual,
|
|
range: sys.range,
|
|
duration: sys.duration,
|
|
spellSave: sys.spellSave,
|
|
wpRank,
|
|
magicRank,
|
|
basePool,
|
|
miracleCountOptions,
|
|
bonusOptions,
|
|
rollModes,
|
|
visibility: game.settings.get("core", "rollMode"),
|
|
}
|
|
|
|
const content = await foundry.applications.handlebars.renderTemplate(
|
|
"systems/fvtt-oath-hammer/templates/miracle-cast-dialog.hbs",
|
|
context
|
|
)
|
|
|
|
const result = await foundry.applications.api.DialogV2.wait({
|
|
window: { title: game.i18n.format("OATHHAMMER.Dialog.MiracleCastTitle", { miracle: miracle.name }) },
|
|
classes: ["fvtt-oath-hammer"],
|
|
content,
|
|
rejectClose: false,
|
|
buttons: [{
|
|
label: game.i18n.localize("OATHHAMMER.Dialog.InvokeMiracle"),
|
|
callback: (_ev, btn) => {
|
|
const out = {}
|
|
for (const el of btn.form.elements) {
|
|
if (!el.name) continue
|
|
out[el.name] = el.type === "checkbox" ? String(el.checked) : el.value
|
|
}
|
|
return out
|
|
},
|
|
}],
|
|
})
|
|
|
|
if (!result) return null
|
|
|
|
const computedDV = isRitual ? dv : (parseInt(result.miracleCount) || 1)
|
|
|
|
return {
|
|
dv: computedDV,
|
|
isRitual,
|
|
bonus: parseInt(result.bonus) || 0,
|
|
visibility: result.visibility ?? game.settings.get("core", "rollMode"),
|
|
explodeOn5: result.explodeOn5 === "true",
|
|
}
|
|
}
|
|
}
|
|
|
|
function _ordinal(n) {
|
|
const s = ["th", "st", "nd", "rd"]
|
|
const v = n % 100
|
|
return s[(v - 20) % 10] ?? s[v] ?? s[0]
|
|
}
|