63770790b9
Arrêter d'utiliser le jQuery $(selector) qui cause des effets de bord si plusieurs élements de la page (ie: foundry) correspondent au selector. Stocker le html dans les Sheet/Dialogs lors de l'appel activateListeners afin de pouvoir s'y référer ensuite. Utiliser this.html.find pour chercher dans le html de la fenêtre courante. Eliminer les référence par id html car l'id est unique (donc ne marche pas en multi-fenêtres)
378 lines
16 KiB
JavaScript
378 lines
16 KiB
JavaScript
import { RollDataAjustements } from "./rolldata-ajustements.js";
|
|
import { HtmlUtility } from "./html-utility.js";
|
|
import { RdDItemCompetence } from "./item-competence.js";
|
|
import { RdDItemSort } from "./item-sort.js";
|
|
import { Misc } from "./misc.js";
|
|
import { RdDBonus } from "./rdd-bonus.js";
|
|
import { RdDCarac } from "./rdd-carac.js";
|
|
import { RdDResolutionTable } from "./rdd-resolution-table.js";
|
|
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
|
|
|
|
/**
|
|
* Extend the base Dialog entity to select roll parameters
|
|
* @extends {Dialog}
|
|
*/
|
|
/* -------------------------------------------- */
|
|
export class RdDRoll extends Dialog {
|
|
|
|
/* -------------------------------------------- */
|
|
static async create(actor, rollData, dialogConfig, action) {
|
|
RdDRoll._ensureCorrectAction(action);
|
|
RdDRoll._setDefaultOptions(actor, rollData);
|
|
|
|
const html = await renderTemplate(dialogConfig.html, rollData);
|
|
|
|
let options = { classes: ["rdd-roll-dialog"], width: 600, height: 'fit-content', 'z-index': 99999, close: html => {} };
|
|
if (dialogConfig.close) {
|
|
options.close = dialogConfig.close;
|
|
}
|
|
return new RdDRoll(actor, rollData, html, options, action);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static _setDefaultOptions(actor, rollData) {
|
|
let defaultRollData = {
|
|
alias: actor.name,
|
|
ajustementsConditions: CONFIG.RDD.ajustementsConditions,
|
|
difficultesLibres: CONFIG.RDD.difficultesLibres,
|
|
etat: actor.getEtatGeneral(),
|
|
moral: actor.getMoralTotal(), /* La valeur du moral pour les jets de volonté */
|
|
carac: actor.system.carac,
|
|
finalLevel: 0,
|
|
diffConditions: 0,
|
|
diffLibre: rollData.competence?.system.default_diffLibre ?? 0,
|
|
perteMoralEchec: false, /* Pour l'affichage dans le chat */
|
|
use: {
|
|
moral: false, /* Est-ce que le joueur demande d'utiliser le moral ? Utile si le joueur change plusieurs fois de carac associée. */
|
|
libre: true,
|
|
conditions: true,
|
|
surenc: actor.isSurenc(),
|
|
encTotal: true
|
|
},
|
|
isMalusEncombrementTotal: RdDItemCompetence.isMalusEncombrementTotal(rollData.competence),
|
|
malusArmureValue: actor.getMalusArmure(),
|
|
surencMalusValue: actor.computeMalusSurEncombrement(),
|
|
encTotal: actor.getEncTotal(),
|
|
ajustementAstrologique: actor.ajustementAstrologique(),
|
|
surprise: actor.getSurprise(false),
|
|
canClose: true,
|
|
isGM: game.user.isGM,
|
|
forceDiceResult: -1
|
|
}
|
|
// Mini patch :Ajout du rêve actuel
|
|
if (actor.system.type == "personnage") {
|
|
defaultRollData.carac["reve-actuel"] = actor.system.reve.reve
|
|
}
|
|
|
|
mergeObject(rollData, defaultRollData, { recursive: true, overwrite: false });
|
|
if (rollData.forceCarac) {
|
|
rollData.carac = rollData.forceCarac;
|
|
}
|
|
rollData.diviseurSignificative = RdDRoll.getDiviseurSignificative(rollData);
|
|
|
|
RollDataAjustements.calcul(rollData, actor);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static getDiviseurSignificative(rollData) {
|
|
let facteurSign = 1;
|
|
if (rollData.surprise == 'demi') {
|
|
facteurSign *= 2;
|
|
}
|
|
if (rollData.needParadeSignificative) {
|
|
facteurSign *= 2;
|
|
}
|
|
if (RdDBonus.isDefenseAttaqueFinesse(rollData)) {
|
|
facteurSign *= 2;
|
|
}
|
|
if (!ReglesOptionelles.isUsing('tripleSignificative')) {
|
|
facteurSign = Math.min(facteurSign, 4);
|
|
}
|
|
return facteurSign;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
static _ensureCorrectAction(action) {
|
|
if (action.callbacks == undefined) {
|
|
console.warn('No callback defined for ', action.name);
|
|
action.callbacks = [{ action: r => console.warn(action.name, r) }];
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
constructor(actor, rollData, html, options, action) {
|
|
let conf = {
|
|
title: action.label,
|
|
content: html,
|
|
buttons: {
|
|
"onAction": {
|
|
label: action.label, callback: html => {
|
|
this.rollData.canClose = true;
|
|
this.onAction(action)
|
|
}
|
|
}
|
|
},
|
|
default: "onAction",
|
|
close: options.close
|
|
};
|
|
super(conf, options);
|
|
|
|
this.actor = actor;
|
|
this.rollData = rollData;
|
|
}
|
|
|
|
activateListeners(html) {
|
|
super.activateListeners(html);
|
|
this.html = html;
|
|
this.bringToTop();
|
|
|
|
console.log('RdDRoll.activateListeners', this.rollData);
|
|
|
|
// Update html, according to rollData
|
|
if (this.rollData.competence) {
|
|
const defaut_carac = this.rollData.competence.system.defaut_carac
|
|
// Set the default carac from the competence item
|
|
this.rollData.selectedCarac = this.rollData.carac[defaut_carac];
|
|
this.html.find("[name='carac']").val(defaut_carac);
|
|
}
|
|
if (this.rollData.selectedSort) {
|
|
this.setSelectedSort(this.rollData.selectedSort);
|
|
this.html.find(".draconic").val(this.rollData.selectedSort.system.listIndex); // Uniquement a la selection du sort, pour permettre de changer
|
|
}
|
|
RdDItemSort.setCoutReveReel(this.rollData.selectedSort);
|
|
this.html.find("[name='diffLibre']").val(Misc.toInt(this.rollData.diffLibre));
|
|
this.html.find("[name='diffConditions']").val(Misc.toInt(this.rollData.diffConditions));
|
|
this.updateRollResult(html);
|
|
|
|
this.html.find("[name='diffLibre']").change((event) => {
|
|
this.rollData.diffLibre = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus
|
|
this.updateRollResult(html);
|
|
});
|
|
this.html.find("[name='diffConditions']").change((event) => {
|
|
this.rollData.diffConditions = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus
|
|
this.updateRollResult(html);
|
|
});
|
|
this.html.find("[name='force-dice-result']").change((event) => {
|
|
this.rollData.forceDiceResult = Misc.toInt(event.currentTarget.value);
|
|
});
|
|
this.html.find("[name='carac']").change((event) => {
|
|
let caracKey = event.currentTarget.value;
|
|
this.rollData.selectedCarac = this.rollData.carac[caracKey]; // Update the selectedCarac
|
|
this.updateRollResult(html);
|
|
});
|
|
this.html.find('.roll-draconic').change((event) => {
|
|
let draconicKey = Misc.toInt(event.currentTarget.value);
|
|
this.rollData.competence = this.rollData.draconicList[draconicKey]; // Update the selectedCarac
|
|
this.updateRollResult(html);
|
|
});
|
|
this.html.find('.roll-sort').change((event) => {
|
|
let sortKey = Misc.toInt(event.currentTarget.value);
|
|
this.setSelectedSort(this.rollData.sortList[sortKey]);
|
|
this.updateRollResult(html);
|
|
this.html.find("[name='diffLibre']").val(this.rollData.diffLibre);
|
|
});
|
|
this.html.find('.roll-carac-competence').change((event) => {
|
|
const competence = event.currentTarget.value;
|
|
this.rollData.competence = this.rollData.competences.find(it => it.name == competence);
|
|
this.updateRollResult(html);
|
|
});
|
|
this.html.find('.roll-signedraconique').change((event) => {
|
|
let sortKey = Misc.toInt(event.currentTarget.value);
|
|
this.setSelectedSigneDraconique(this.rollData.signes[sortKey]);
|
|
this.updateRollResult(html);
|
|
});
|
|
this.html.find("[name='ptreve-variable']").change((event) => {
|
|
let ptreve = Misc.toInt(event.currentTarget.value);
|
|
this.rollData.selectedSort.system.ptreve_reel = ptreve;
|
|
console.log("RdDRollSelectDialog - Cout reve", ptreve);
|
|
this.updateRollResult(html);
|
|
});
|
|
this.html.find("[name='coupsNonMortels']").change((event) => {
|
|
this.rollData.dmg.mortalite = event.currentTarget.checked ? "non-mortel" : "mortel";
|
|
this.updateRollResult(html);
|
|
});
|
|
this.html.find('.cuisine-proportions').change((event) => {
|
|
this.rollData.proportions = Number(event.currentTarget.value);
|
|
this.updateRollResult(html);
|
|
});
|
|
this.html.find('.select-by-name').change((event) => {
|
|
const attribute = event.currentTarget.attributes['name'].value;
|
|
this.rollData[attribute] = event.currentTarget.value;
|
|
this.updateRollResult(html);
|
|
});
|
|
this.html.find('.checkbox-by-name').change((event) => {
|
|
const attribute = event.currentTarget.attributes['name'].value;
|
|
this.rollData[attribute] = event.currentTarget.checked;
|
|
this.updateRollResult(html);
|
|
});
|
|
this.html.find('input.use-encTotal').change((event) => {
|
|
this.rollData.use.encTotal = event.currentTarget.checked;
|
|
this.updateRollResult(html);
|
|
});
|
|
this.html.find('input.use-surenc').change((event) => {
|
|
this.rollData.use.surenc = event.currentTarget.checked;
|
|
this.updateRollResult(html);
|
|
});
|
|
this.html.find('.appel-moral').click((event) => { /* l'appel au moral, qui donne un bonus de +1 */
|
|
this.rollData.use.moral = !this.rollData.use.moral;
|
|
const appelMoral = this.html.find('.icon-appel-moral')[0];
|
|
const tooltip = this.html.find('.tooltipAppelAuMoralText')[0];
|
|
if (this.rollData.use.moral) {
|
|
if (this.rollData.moral > 0) {
|
|
tooltip.innerHTML = "Appel au moral";
|
|
appelMoral.src = "/systems/foundryvtt-reve-de-dragon/icons/moral-heureux.svg";
|
|
} else {
|
|
tooltip.innerHTML = "Appel à l'énergie du désespoir";
|
|
appelMoral.src = "/systems/foundryvtt-reve-de-dragon/icons/moral-malheureux.svg";
|
|
}
|
|
} else {
|
|
tooltip.innerHTML = "Sans appel au moral";
|
|
appelMoral.src = "/systems/foundryvtt-reve-de-dragon/icons/moral-neutre.svg";
|
|
}
|
|
this.updateRollResult(html);
|
|
});
|
|
// Section Méditation
|
|
this.html.find('.conditionMeditation').change((event) => {
|
|
let condition = event.currentTarget.attributes['name'].value;
|
|
this.rollData.conditionMeditation[condition] = event.currentTarget.checked;
|
|
this.updateRollResult(html);
|
|
});
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
close() {
|
|
if (this.rollData.canClose) {
|
|
return super.close();
|
|
}
|
|
ui.notifications.info("Vous devez faire ce jet de dés!");
|
|
}
|
|
|
|
async onAction(action) {
|
|
this.rollData.forceDiceResult = Number.parseInt(this.html.find("[name='force-dice-result']").val()) ?? -1;
|
|
await RdDResolutionTable.rollData(this.rollData);
|
|
console.log("RdDRoll -=>", this.rollData, this.rollData.rolled);
|
|
if (action.callbacks)
|
|
for (let callback of action.callbacks) {
|
|
if (callback.condition == undefined || callback.condition(this.rollData)) {
|
|
await callback.action(this.rollData);
|
|
}
|
|
}
|
|
}
|
|
|
|
async setSelectedSort(sort) {
|
|
this.rollData.selectedSort = sort; // Update the selectedCarac
|
|
this.rollData.competence = RdDItemCompetence.getVoieDraconic(this.rollData.draconicList, sort.system.draconic);
|
|
this.rollData.bonus = RdDItemSort.getCaseBonus(sort, this.rollData.tmr.coord);
|
|
this.rollData.diffLibre = RdDItemSort.getDifficulte(sort, -7);
|
|
RdDItemSort.setCoutReveReel(sort);
|
|
const htmlSortDescription = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/partial-description-sort.html", { sort: sort });
|
|
this.html.find(".sort-ou-rituel").text(sort.system.isrituel ? "rituel" : "sort");
|
|
this.html.find(".bonus-case").text(`${this.rollData.bonus}%`);
|
|
this.html.find(".placeholder-description-sort").children().remove();
|
|
this.html.find(".placeholder-description-sort").append(htmlSortDescription);
|
|
this.html.find(".roll-draconic").val(sort.system.listIndex);
|
|
this.html.find(".div-sort-difficulte-fixe").text(Misc.toSignedString(sort.system.difficulte));
|
|
this.html.find(".div-sort-ptreve-fixe").text(sort.system.ptreve);
|
|
const diffVariable = RdDItemSort.isDifficulteVariable(sort);
|
|
const coutVariable = RdDItemSort.isCoutVariable(sort);
|
|
|
|
HtmlUtility._showControlWhen(this.html.find(".div-sort-non-rituel"), !sort.system.isrituel);
|
|
HtmlUtility._showControlWhen(this.html.find(".div-sort-difficulte-var"), diffVariable);
|
|
HtmlUtility._showControlWhen(this.html.find(".div-sort-difficulte-fixe"), !diffVariable);
|
|
HtmlUtility._showControlWhen(this.html.find(".div-sort-ptreve-var"), coutVariable);
|
|
HtmlUtility._showControlWhen(this.html.find(".div-sort-ptreve-fixe"), !coutVariable);
|
|
}
|
|
|
|
async setSelectedSigneDraconique(signe) {
|
|
this.rollData.signe = signe;
|
|
this.rollData.diffLibre = signe.system.difficulte,
|
|
$(".signe-difficulte").text(Misc.toSignedString(this.rollData.diffLibre));
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
async updateRollResult(html) {
|
|
let rollData = this.rollData;
|
|
|
|
rollData.dmg = rollData.attackerRoll?.dmg ?? RdDBonus.dmg(rollData, this.actor.getBonusDegat())
|
|
rollData.caracValue = parseInt(rollData.selectedCarac.value)
|
|
rollData.mortalite = rollData.attackerRoll?.dmg.mortalite ?? rollData.dmg.mortalite ?? 'mortel';
|
|
rollData.coupsNonMortels = (rollData.attackerRoll?.dmg.mortalite ?? rollData.dmg.mortalite) == 'non-mortel';
|
|
rollData.use.appelAuMoral = this.actor.isPersonnage() && RdDCarac.isActionPhysique(rollData.selectedCarac);
|
|
let dmgText = Misc.toSignedString(rollData.dmg.total);
|
|
|
|
switch (rollData.mortalite) {
|
|
case 'non-mortel': dmgText = `(${dmgText}) non-mortel`; break;
|
|
case 'empoignade': dmgText = `empoignade`; break;
|
|
}
|
|
|
|
RollDataAjustements.calcul(rollData, this.actor);
|
|
rollData.finalLevel = this._computeFinalLevel(rollData);
|
|
|
|
const resolutionTable = await RdDResolutionTable.buildHTMLTable(RdDResolutionTable.subTable(rollData.caracValue, rollData.finalLevel))
|
|
const adjustements = await this.buildAjustements(rollData);
|
|
|
|
HtmlUtility._showControlWhen(this.html.find(".use-encTotal"), rollData.ajustements.encTotal.visible && RdDCarac.isAgiliteOuDerivee(rollData.selectedCarac));
|
|
HtmlUtility._showControlWhen(this.html.find(".use-surenc"), rollData.ajustements.surenc.visible && RdDCarac.isActionPhysique(rollData.selectedCarac));
|
|
HtmlUtility._showControlWhen(this.html.find(".utilisation-moral"), rollData.use.appelAuMoral);
|
|
HtmlUtility._showControlWhen(this.html.find(".diffMoral"), rollData.ajustements.moralTotal.used);
|
|
HtmlUtility._showControlWhen(this.html.find(".divAppelAuMoral"), rollData.use.appelAuMoral);
|
|
|
|
// Mise à jour valeurs
|
|
this.html.find(".dialog-roll-title").text(this._getTitle(rollData));
|
|
this.html.find("[name='coupsNonMortels']").prop('checked', rollData.mortalite == 'non-mortel');
|
|
this.html.find(".dmg-arme-actor").text(dmgText);
|
|
this.html.find("div.placeholder-ajustements").empty().append(adjustements);
|
|
this.html.find("div.placeholder-resolution").empty().append(resolutionTable)
|
|
}
|
|
|
|
|
|
/* -------------------------------------------- */
|
|
async buildAjustements(rollData) {
|
|
return await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.html`, rollData);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
_computeFinalLevel(rollData) {
|
|
return RollDataAjustements.sum(rollData.ajustements);
|
|
}
|
|
/* -------------------------------------------- */
|
|
_computeDiffCompetence(rollData) {
|
|
if (rollData.competence) {
|
|
return Misc.toInt(rollData.competence.system.niveau);
|
|
}
|
|
if (rollData.draconicList) {
|
|
return Misc.toInt(rollData.competence.system.niveau);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
_computeMalusArmure(rollData) {
|
|
let malusArmureValue = 0;
|
|
if (rollData.malusArmureValue && (rollData.selectedCarac.label == "Agilité" || rollData.selectedCarac.label == "Dérobée")) {
|
|
malusArmureValue = rollData.malusArmureValue;
|
|
}
|
|
return malusArmureValue;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
_getTitle(rollData) {
|
|
const carac = rollData.selectedCarac.label;
|
|
if (!rollData.competence) {
|
|
return carac;
|
|
}
|
|
const compName = rollData.competence.name;
|
|
if (rollData.draconicList && rollData.selectedSort) {
|
|
return compName + " - " + rollData.selectedSort.name;
|
|
}
|
|
// If a weapon is there, add it in the title
|
|
const niveau = Misc.toSignedString(rollData.competence.system.niveau)
|
|
if (compName == carac) {
|
|
// cas des créatures
|
|
return carac + " Niveau " + niveau
|
|
}
|
|
const armeTitle = (rollData.arme) ? " (" + rollData.arme.name + ") " : "";
|
|
return carac + "/" + compName + armeTitle + " Niveau " + niveau
|
|
}
|
|
}
|