335 lines
11 KiB
JavaScript
335 lines
11 KiB
JavaScript
import { YggdrasillUtility } from "../yggdrasill-utility.js"
|
|
|
|
const dureeGaldrSD = { "1d5a": 3, "1d10t": 6, "1d10m": 9, "1d10h": 12, "1d5j": 15}
|
|
const ciblesGaldrSD = { "1": 3, "2_4": 6, "5_9": 9, "10_49": 12, "50plus": 15}
|
|
const zonesciblesGaldrSD = { "INS10cm3": 3, "INS50cm3": 6, "INS1m3": 9, "INS5m3": 12, "INS10m3": 15}
|
|
|
|
/**
|
|
* Dialogue de jet de dé pour Yggdrasill - Version DialogV2
|
|
*/
|
|
export class YggdrasillRollDialog {
|
|
|
|
/**
|
|
* Create and display the roll dialog
|
|
* @param {YggdrasillActor} actor - The actor making the roll
|
|
* @param {Object} rollData - Data for the roll
|
|
* @returns {Promise}
|
|
*/
|
|
static async create(actor, rollData) {
|
|
// Initialiser attackData pour les armes si nécessaire
|
|
if ((rollData.mode === "armecc" || rollData.mode === "armetir" || rollData.mode === "armedist") && rollData.attackDef) {
|
|
// Les données sont déjà calculées dans attackDef par getAttaqueData/getTirData
|
|
// On les copie simplement dans attackData pour le template
|
|
rollData.attackData = { ...rollData.attackDef }
|
|
}
|
|
|
|
// Calculer srTotal pour les sorts
|
|
if (rollData.mode === "galdr") {
|
|
this._updateGaldrSD(rollData)
|
|
rollData.srTotal = 14 + (rollData.sdGaldr || 0)
|
|
} else if (rollData.mode === "sejdr") {
|
|
rollData.srTotal = 14 + (rollData.bonusdefense || 0)
|
|
} else if (rollData.mode === "rune") {
|
|
this._updateRuneData(rollData, actor)
|
|
}
|
|
|
|
// Préparer le contexte pour le template
|
|
const context = {
|
|
...rollData,
|
|
img: actor.img,
|
|
name: actor.name,
|
|
config: game.system.yggdrasill.config,
|
|
}
|
|
|
|
// Titre selon le mode
|
|
let title = "Test"
|
|
if (rollData.mode === "competence") title = "Test de Compétence"
|
|
else if (rollData.mode === "carac") title = "Test de Caractéristique"
|
|
else if (rollData.mode === "attribut") title = "Test d'Attribut"
|
|
else if (rollData.mode === "armecc") title = "Attaque au Corps à Corps"
|
|
else if (rollData.mode === "armetir" || rollData.mode === "armedist") title = "Attaque à Distance"
|
|
else if (rollData.mode === "sejdr") title = "Sort Sejdr"
|
|
else if (rollData.mode === "galdr") title = "Sort Galdr"
|
|
else if (rollData.mode === "rune") title = "Rune"
|
|
|
|
// Rendre le template en HTML
|
|
const content = await foundry.applications.handlebars.renderTemplate(
|
|
"systems/fvtt-yggdrasill/templates/roll-dialog-generic-new.hbs",
|
|
context
|
|
)
|
|
|
|
// Utiliser DialogV2.wait avec le HTML rendu
|
|
return foundry.applications.api.DialogV2.wait({
|
|
window: {
|
|
title: title,
|
|
icon: "fa-solid fa-dice-d20"
|
|
},
|
|
classes: ["yggdrasill-roll-dialog"],
|
|
position: { width: 600 },
|
|
modal: false,
|
|
content,
|
|
buttons: [
|
|
{
|
|
action: "roll",
|
|
label: "Lancer le Test",
|
|
icon: "fa-solid fa-dice",
|
|
default: true,
|
|
callback: (event, button, dialog) => {
|
|
this._updateRollDataFromForm(rollData, button.form.elements, actor)
|
|
this._performRoll(rollData)
|
|
}
|
|
},
|
|
],
|
|
actions: {},
|
|
render: (event, dialog) => {
|
|
// Pour Galdr: recalculer srTotal quand durée, cibles ou zone changent
|
|
if (rollData.mode === "galdr") {
|
|
$("#dureeGaldr, #nbCibles, #zoneGaldr").on("change", () => {
|
|
rollData.dureeGaldr = $("#dureeGaldr").val()
|
|
rollData.nbCibles = $("#nbCibles").val()
|
|
rollData.zoneGaldr = $("#zoneGaldr").val()
|
|
this._updateGaldrSD(rollData)
|
|
rollData.srTotal = 14 + (rollData.sdGaldr || 0)
|
|
$("#srTotal").text(rollData.srTotal)
|
|
})
|
|
}
|
|
|
|
// Pour Sejdr: recalculer srTotal quand DM change
|
|
if (rollData.mode === "sejdr") {
|
|
$("#bonusdefense").on("change", () => {
|
|
rollData.bonusdefense = parseInt($("#bonusdefense").val()) || 0
|
|
rollData.srTotal = 14 + rollData.bonusdefense
|
|
$("#srTotal").text(rollData.srTotal)
|
|
})
|
|
}
|
|
|
|
// Pour Rune: recalculer srTotal quand support ou puissance changent
|
|
if (rollData.mode === "rune") {
|
|
$("#supportRune, #puissanceRune").on("change", () => {
|
|
rollData.supportRune = $("#supportRune").val()
|
|
rollData.puissanceRune = parseInt($("#puissanceRune").val()) || 1
|
|
this._updateRuneData(rollData, actor)
|
|
$("#runeDuree").text(rollData.runeDuree)
|
|
$("#runeDureeVie").text(rollData.runeDureeVie)
|
|
$("#srTotal").text(rollData.srTotal)
|
|
})
|
|
}
|
|
},
|
|
rejectClose: false,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Perform the roll based on mode
|
|
* @param {Object} rollData - The roll data
|
|
* @private
|
|
*/
|
|
static _performRoll(rollData) {
|
|
if (rollData.mode === "attribut") {
|
|
YggdrasillUtility.rollAttribute(rollData)
|
|
} else {
|
|
YggdrasillUtility.rollYggdrasill(rollData)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mettre à jour rollData avec les valeurs du formulaire
|
|
* @param {Object} rollData - L'objet rollData à mettre à jour
|
|
* @param {HTMLFormControlsCollection} formElements - Les éléments du formulaire
|
|
* @param {YggdrasillActor} actor - L'acteur pour récupérer les données
|
|
* @private
|
|
*/
|
|
static _updateRollDataFromForm(rollData, formElements, actor) {
|
|
// Caractéristique (pour compétences)
|
|
if (formElements.caracName) {
|
|
const caracKey = formElements.caracName.value
|
|
rollData.caracName = caracKey
|
|
rollData.selectedCarac = this._findCaracByKey(actor, caracKey)
|
|
}
|
|
|
|
// Type d'attaque (pour armes)
|
|
if (formElements.typeAttack) {
|
|
rollData.attackDef = rollData.attackDef || {}
|
|
rollData.attackDef.typeAttack = formElements.typeAttack.value
|
|
this._updateAttackData(rollData, actor)
|
|
}
|
|
|
|
// Bonus/Malus
|
|
if (formElements.bonusMalus) {
|
|
rollData.bonusMalus = parseInt(formElements.bonusMalus.value) || 0
|
|
}
|
|
|
|
// Furor
|
|
if (formElements.furorUsage) {
|
|
rollData.furorUsage = parseInt(formElements.furorUsage.value) || 0
|
|
}
|
|
|
|
// Seuil de Réussite
|
|
if (formElements.sr) {
|
|
rollData.sr = parseInt(formElements.sr.value) || 9
|
|
}
|
|
|
|
// Galdr options
|
|
if (formElements.dureeGaldr) {
|
|
rollData.dureeGaldr = formElements.dureeGaldr.value
|
|
}
|
|
if (formElements.nbCibles) {
|
|
rollData.nbCibles = formElements.nbCibles.value
|
|
}
|
|
if (formElements.zoneGaldr) {
|
|
rollData.zoneGaldr = formElements.zoneGaldr.value
|
|
}
|
|
if (rollData.mode === "galdr") {
|
|
this._updateGaldrSD(rollData)
|
|
rollData.srTotal = 14 + (rollData.sdGaldr || 0)
|
|
}
|
|
|
|
// Sejdr options
|
|
if (formElements.bonusdefense) {
|
|
rollData.bonusdefense = parseInt(formElements.bonusdefense.value) || 0
|
|
}
|
|
if (rollData.mode === "sejdr") {
|
|
rollData.srTotal = 14 + (rollData.bonusdefense || 0)
|
|
}
|
|
|
|
// Rune options
|
|
if (formElements.runeDuree) {
|
|
rollData.runeDuree = formElements.runeDuree.value
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find characteristic by key in actor
|
|
* @param {YggdrasillActor} actor
|
|
* @param {String} caracKey
|
|
* @returns {Object}
|
|
* @private
|
|
*/
|
|
static _findCaracByKey(actor, caracKey) {
|
|
for (let [categKey, categ] of Object.entries(actor.system.carac)) {
|
|
for (let [key, carac] of Object.entries(categ.carac)) {
|
|
if (key === caracKey) {
|
|
return { ...carac, categName: categKey, caracName: key }
|
|
}
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
/**
|
|
* Update attack data based on attack type
|
|
* @param {Object} rollData
|
|
* @param {YggdrasillActor} actor
|
|
* @private
|
|
*/
|
|
static _updateAttackData(rollData, actor) {
|
|
const config = game.system.yggdrasill.config
|
|
const attackType = rollData.attackDef.typeAttack
|
|
const attackMode = config.attackMode?.[attackType]
|
|
|
|
if (attackMode) {
|
|
rollData.attackData = rollData.attackData || {}
|
|
rollData.attackData.categName = attackMode.categName
|
|
rollData.attackData.caracName = attackMode.caracName
|
|
rollData.attackData.malus = this._computeValue(attackMode.malus, actor)
|
|
rollData.attackData.bonusdegats = this._computeValue(attackMode.bonusdegats, actor)
|
|
rollData.attackData.protection = this._computeValue(attackMode.protection, actor)
|
|
rollData.attackData.label = attackMode.label
|
|
rollData.attackData.description = attackMode.description
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Compute value from string formula like "puissance;3"
|
|
* @param {String|Number} value
|
|
* @param {YggdrasillActor} actor
|
|
* @returns {Number}
|
|
* @private
|
|
*/
|
|
static _computeValue(value, actor) {
|
|
if (typeof value === 'number') return value
|
|
if (!value || value === "0") return 0
|
|
|
|
const parts = String(value).split(';')
|
|
if (parts.length === 2) {
|
|
const caracName = parts[0]
|
|
const multiplier = parseInt(parts[1]) || 1
|
|
const caracValue = this._getCaracValue(actor, caracName)
|
|
return caracValue * multiplier
|
|
}
|
|
return 0
|
|
}
|
|
|
|
/**
|
|
* Get characteristic value by name
|
|
* @param {YggdrasillActor} actor
|
|
* @param {String} caracName
|
|
* @returns {Number}
|
|
* @private
|
|
*/
|
|
static _getCaracValue(actor, caracName) {
|
|
for (let categ of Object.values(actor.system.carac)) {
|
|
if (categ.carac && categ.carac[caracName]) {
|
|
return categ.carac[caracName].value || 0
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
/**
|
|
* Update rune data based on support and power
|
|
* @param {Object} rollData
|
|
* @param {YggdrasillActor} actor
|
|
* @private
|
|
*/
|
|
static _updateRuneData(rollData, actor) {
|
|
let support = 0
|
|
|
|
rollData.dureeRune = 6 - (rollData.agiliteCarac?.value || 0)
|
|
|
|
if (rollData.supportRune === "peau") {
|
|
support = 3
|
|
rollData.echelleDuree = "Actions"
|
|
rollData.echelleDureeVie = "Heures"
|
|
} else if (rollData.supportRune === "tissu") {
|
|
support = 6
|
|
rollData.echelleDuree = "Tours"
|
|
rollData.echelleDureeVie = "Jours"
|
|
} else if (rollData.supportRune === "cuir") {
|
|
support = 9
|
|
rollData.echelleDuree = "Minutes"
|
|
rollData.echelleDureeVie = "Semaines"
|
|
} else if (rollData.supportRune === "bois") {
|
|
support = 12
|
|
rollData.echelleDuree = "Heures"
|
|
rollData.echelleDureeVie = "Mois"
|
|
} else if (rollData.supportRune === "pierremetal") {
|
|
support = 15
|
|
rollData.echelleDuree = "Jours"
|
|
rollData.echelleDureeVie = "Années"
|
|
}
|
|
|
|
rollData.runeDuree = `${rollData.dureeRune} ${rollData.echelleDuree}`
|
|
rollData.runeDureeVie = `${rollData.competence?.system.niveau || 1} ${rollData.echelleDureeVie}`
|
|
rollData.srTotal = (rollData.puissanceRune || 1) + (Number(rollData.sort?.system.niveau || 0) * 3) + support
|
|
}
|
|
|
|
/**
|
|
* Update Galdr SD based on duration and targets
|
|
* @param {Object} rollData
|
|
* @private
|
|
*/
|
|
static _updateGaldrSD(rollData) {
|
|
let sdDuree = Number(dureeGaldrSD[rollData.dureeGaldr]) || 0
|
|
let sdVar = 0
|
|
|
|
if (rollData.sort?.system.voie === "illusion") {
|
|
sdVar = Number(zonesciblesGaldrSD[rollData.zoneGaldr]) || 0
|
|
} else {
|
|
sdVar = Number(ciblesGaldrSD[rollData.nbCibles]) || 0
|
|
}
|
|
|
|
rollData.sdGaldr = sdDuree + sdVar
|
|
}
|
|
}
|