Add roll windows from actor sheet
This commit is contained in:
118
module/applications/spell-dialog.mjs
Normal file
118
module/applications/spell-dialog.mjs
Normal file
@@ -0,0 +1,118 @@
|
||||
import { SYSTEM } from "../config/system.mjs"
|
||||
|
||||
/**
|
||||
* Spell enhancements — applied before casting (p.96-97).
|
||||
* stress: Arcane Stress cost regardless of roll result
|
||||
* penalty: dice pool penalty
|
||||
* redDice: true = roll red dice (3+ threshold) on the check
|
||||
* noStress: true = 1s rolled do NOT add Arcane Stress (Safe Spell)
|
||||
*/
|
||||
export const SPELL_ENHANCEMENTS = {
|
||||
none: { label: "OATHHAMMER.Enhancement.None", stress: 0, penalty: 0, redDice: false, noStress: false },
|
||||
focused: { label: "OATHHAMMER.Enhancement.Focused", stress: 1, penalty: 0, redDice: true, noStress: false },
|
||||
controlled: { label: "OATHHAMMER.Enhancement.Controlled", stress: 1, penalty: 0, redDice: false, noStress: false },
|
||||
empowered: { label: "OATHHAMMER.Enhancement.Empowered", stress: 2, penalty: 0, redDice: false, noStress: false },
|
||||
extended: { label: "OATHHAMMER.Enhancement.Extended", stress: 1, penalty: -1, redDice: false, noStress: false },
|
||||
penetrating: { label: "OATHHAMMER.Enhancement.Penetrating", stress: 1, penalty: -1, redDice: false, noStress: false },
|
||||
lethal: { label: "OATHHAMMER.Enhancement.Lethal", stress: 2, penalty: -2, redDice: false, noStress: false },
|
||||
hastened: { label: "OATHHAMMER.Enhancement.Hastened", stress: 3, penalty: -3, redDice: false, noStress: false },
|
||||
safe: { label: "OATHHAMMER.Enhancement.Safe", stress: 0, penalty: -3, redDice: false, noStress: true },
|
||||
}
|
||||
|
||||
export default class OathHammerSpellDialog {
|
||||
|
||||
static async prompt(actor, spell) {
|
||||
const sys = spell.system
|
||||
const actorSys = actor.system
|
||||
|
||||
const intRank = actorSys.attributes.intelligence.rank
|
||||
const magicRank = actorSys.skills.magic.rank
|
||||
const basePool = intRank + magicRank
|
||||
|
||||
const currentStress = actorSys.arcaneStress.value
|
||||
const stressThreshold = actorSys.arcaneStress.threshold
|
||||
const isOverThreshold = currentStress >= stressThreshold
|
||||
|
||||
const isElemental = sys.tradition === "elemental"
|
||||
const dv = sys.difficultyValue
|
||||
|
||||
const traditionLabel = (() => {
|
||||
const entry = SYSTEM.SORCEROUS_TRADITIONS?.[sys.tradition]
|
||||
return entry ? game.i18n.localize(entry.label) : (sys.tradition ?? "")
|
||||
})()
|
||||
|
||||
const enhancementOptions = Object.entries(SPELL_ENHANCEMENTS).map(([key, def]) => ({
|
||||
value: key,
|
||||
label: game.i18n.localize(def.label),
|
||||
selected: key === "none",
|
||||
}))
|
||||
|
||||
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,
|
||||
spellName: spell.name,
|
||||
spellImg: spell.img,
|
||||
dv,
|
||||
traditionLabel,
|
||||
isRitual: sys.isRitual,
|
||||
isMagicMissile: sys.isMagicMissile,
|
||||
range: sys.range,
|
||||
duration: sys.duration,
|
||||
spellSave: sys.spellSave,
|
||||
isElemental,
|
||||
element: sys.element,
|
||||
intRank,
|
||||
magicRank,
|
||||
basePool,
|
||||
currentStress,
|
||||
stressThreshold,
|
||||
isOverThreshold,
|
||||
enhancementOptions,
|
||||
bonusOptions,
|
||||
rollModes,
|
||||
visibility: game.settings.get("core", "rollMode"),
|
||||
}
|
||||
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
"systems/fvtt-oath-hammer/templates/spell-cast-dialog.hbs",
|
||||
context
|
||||
)
|
||||
|
||||
const result = await foundry.applications.api.DialogV2.wait({
|
||||
window: { title: game.i18n.format("OATHHAMMER.Dialog.SpellCastTitle", { spell: spell.name }) },
|
||||
classes: ["fvtt-oath-hammer"],
|
||||
content,
|
||||
rejectClose: false,
|
||||
buttons: [{
|
||||
label: game.i18n.localize("OATHHAMMER.Dialog.CastSpell"),
|
||||
callback: (_ev, btn) => Object.fromEntries(
|
||||
[...btn.form.elements].filter(e => e.name).map(e => [e.name, e.value])
|
||||
),
|
||||
}],
|
||||
})
|
||||
|
||||
if (!result) return null
|
||||
|
||||
const enhKey = result.enhancement ?? "none"
|
||||
const enh = SPELL_ENHANCEMENTS[enhKey] ?? SPELL_ENHANCEMENTS.none
|
||||
|
||||
return {
|
||||
dv,
|
||||
enhancement: enhKey,
|
||||
stressCost: enh.stress,
|
||||
poolPenalty: enh.penalty,
|
||||
redDice: enh.redDice,
|
||||
noStress: enh.noStress,
|
||||
elementalBonus: parseInt(result.elementalBonus) || 0,
|
||||
bonus: parseInt(result.bonus) || 0,
|
||||
grimPenalty: parseInt(result.noGrimoire) || 0,
|
||||
visibility: result.visibility ?? game.settings.get("core", "rollMode"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user