Vincent Vandemeulebrouck
b7cb0f0752
La recherche était case-sensitive, du coup corriger le nom de la compétence 'Epées' dans le compendium des compétences rend les Épées inutilisable (et échec au chargement de la fiche)
371 lines
16 KiB
JavaScript
371 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 { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
|
import { Grammar } from "./grammar.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: 650, 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.getAlias(),
|
|
ajustementsConditions: CONFIG.RDD.ajustementsConditions,
|
|
difficultesLibres: CONFIG.RDD.difficultesLibres,
|
|
etat: actor.getEtatGeneral(),
|
|
moral: actor.getMoralTotal(), /* La valeur du moral pour les jets de volonté */
|
|
amoureux: actor.listeSuivants(it => it.coeur > 0),
|
|
carac: actor.system.carac,
|
|
finalLevel: 0,
|
|
diffConditions: 0,
|
|
diffLibre: rollData.competence?.system.default_diffLibre ?? 0,
|
|
perteMoralEchec: false, /* Pour l'affichage dans le chat */
|
|
use: {
|
|
astrologique: true,
|
|
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,
|
|
coeur: undefined,
|
|
conditions: true,
|
|
surenc: actor.isSurenc(),
|
|
encTotal: true
|
|
},
|
|
isMalusEncombrementTotal: RdDItemCompetence.isMalusEncombrementTotal(rollData.competence),
|
|
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
|
|
}
|
|
|
|
foundry.utils.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 (!ReglesOptionnelles.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 => Grammar.equalsInsensitive(it.name, competence))
|
|
this.updateRollResult(html);
|
|
});
|
|
this.html.find('.select-suivant-coeur').change((event) => {
|
|
const selectedActorId = event.currentTarget.value;
|
|
this.rollData.use.coeur = this.actor.getSuivant(selectedActorId)
|
|
if (this.rollData.use.coeur) {
|
|
this.html.find(".utilisation-coeur img.selected-suivant-coeur").attr('src', this.rollData.use.coeur?.img)
|
|
this.html.find(".utilisation-coeur img.selected-suivant-coeur").attr('title', this.rollData.use.coeur?.name)
|
|
}
|
|
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("input.check-mortalite").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-astrologique').change((event) => {
|
|
this.rollData.use.astrologique = 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) {
|
|
const rollData = this.rollData;
|
|
|
|
rollData.dmg = rollData.attackerRoll?.dmg ?? RdDBonus.dmg(rollData, this.actor)
|
|
rollData.caracValue = parseInt(rollData.selectedCarac.value)
|
|
rollData.dmg.mortalite = rollData.dmg.mortalite ?? 'mortel';
|
|
rollData.use.appelAuMoral = this.actor.isPersonnage() && RdDCarac.isActionPhysique(rollData.selectedCarac);
|
|
|
|
RollDataAjustements.calcul(rollData, this.actor);
|
|
|
|
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.isAgiliteOuDerobee(rollData.selectedCarac));
|
|
HtmlUtility.showControlWhen(this.html.find(".use-surenc"), rollData.ajustements.surenc.visible && RdDCarac.isActionPhysique(rollData.selectedCarac));
|
|
HtmlUtility.showControlWhen(this.html.find(".use-astrologique"), rollData.ajustements.astrologique.visible);
|
|
HtmlUtility.showControlWhen(this.html.find(".utilisation-moral"), rollData.use.appelAuMoral);
|
|
HtmlUtility.showControlWhen(this.html.find(".divAppelAuMoral"), rollData.use.appelAuMoral);
|
|
HtmlUtility.showControlWhen(this.html.find(".utilisation-coeur"), rollData.ajustements.coeur.visible);
|
|
HtmlUtility.showControlWhen(this.html.find(".utilisation-coeur img.selected-suivant-coeur"), rollData.ajustements.coeur.visible && rollData.use.coeur != undefined)
|
|
// HtmlUtility.showControlWhen(this.html.find(".diffMoral"), rollData.ajustements.moral.used);
|
|
|
|
// Mise à jour valeurs
|
|
this.html.find(".dialog-roll-title").text(this._getTitle(rollData));
|
|
this.html.find("input.check-mortalite").prop('checked', rollData.dmg.mortalite == 'non-mortel');
|
|
this.html.find("label.dmg-arme-actor").text(rollData.dmg.mortalite == 'empoignade' ? 'empoignade' : Misc.toSignedString(rollData.dmg.total));
|
|
this.html.find("label.arme-mortalite").text(rollData.dmg.mortalite);
|
|
// this.html.find("[name='dmg-arme-actor']").text(rollData.dmg.mortalite == 'empoignade'? 'empoignade': Misc.toSignedString(rollData.dmg.total) );
|
|
// this.html.find("[name='arme-mortalite']").text(rollData.dmg.mortalite);
|
|
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);
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
_getTitle(rollData) {
|
|
const alias = rollData.alias
|
|
const carac = rollData.selectedCarac.label;
|
|
if (!rollData.competence) {
|
|
return `${alias}: ${carac}`
|
|
}
|
|
const compName = rollData.competence.name;
|
|
const niveau = Misc.toSignedString(rollData.competence.system.niveau)
|
|
if (compName == carac) {
|
|
// cas des créatures
|
|
return `${alias}: ${carac} Niveau ${niveau}`
|
|
}
|
|
if (rollData.draconicList && rollData.selectedSort) {
|
|
// cas de lancer de sort
|
|
return `${alias}: ${rollData.competence.name} Niveau ${niveau} ${rollData.selectedSort.name}`
|
|
}
|
|
if (rollData.arme && rollData.arme.name != compName) {
|
|
// ajouter l'arme au titre si son nom n'est pas la compétence
|
|
return `${alias}: ${carac} / ${compName} (${rollData.arme.name}) Niveau ${niveau}`
|
|
}
|
|
return `${alias}: ${carac} / ${compName} Niveau ${niveau}`
|
|
}
|
|
}
|