foundryvtt-reve-de-dragon/module/rdd-resolution-table.js
Vincent Vandemeulebrouck df5954bf75 Fix reférence circulaire
La méthode rollData fait le jet fourni dans rollData et l'ajoute dans
rollData.rolled.

Pas besoin de retourner rollData, la tentation est forte de mettre le
résultat dans "rolled"
2020-12-09 00:36:59 +01:00

274 lines
11 KiB
JavaScript

import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
/**
* difficultés au delà de -10
*/
const levelDown = [
{ level: -11, score: 1, sign: 0, part: 0, epart: 2, etotal: 90 },
{ level: -12, score: 1, sign: 0, part: 0, epart: 2, etotal: 70 },
{ level: -13, score: 1, sign: 0, part: 0, epart: 2, etotal: 50 },
{ level: -14, score: 1, sign: 0, part: 0, epart: 2, etotal: 30 },
{ level: -15, score: 1, sign: 0, part: 0, epart: 2, etotal: 10 },
{ level: -16, score: 1, sign: 0, part: 0, epart: 0, etotal: 2 }
];
const levelImpossible = { score: 0, sign: 0, part: 0, epart: 0, etotal: 1 };
/**
* Table des résultats spéciaux - inutilisée, conservée si on veut afficher la table
*/
const specialResults = [
{ part: 0, epart: 0, etotal: 0, min: 0, max: 0 },
{ part: 1, epart: 81, etotal: 92, min: 1, max: 5 },
{ part: 2, epart: 82, etotal: 92, min: 6, max: 10 },
{ part: 3, epart: 83, etotal: 93, min: 11, max: 15 },
{ part: 4, epart: 84, etotal: 93, min: 16, max: 20 },
{ part: 5, epart: 85, etotal: 94, min: 21, max: 25 },
{ part: 6, epart: 86, etotal: 94, min: 26, max: 30 },
{ part: 7, epart: 87, etotal: 95, min: 31, max: 35 },
{ part: 8, epart: 88, etotal: 95, min: 36, max: 40 },
{ part: 9, epart: 89, etotal: 96, min: 41, max: 45 },
{ part: 10, epart: 90, etotal: 96, min: 46, max: 50 },
{ part: 11, epart: 91, etotal: 97, min: 51, max: 55 },
{ part: 12, epart: 92, etotal: 97, min: 56, max: 60 },
{ part: 13, epart: 93, etotal: 98, min: 61, max: 65 },
{ part: 14, epart: 94, etotal: 98, min: 65, max: 70 },
{ part: 15, epart: 95, etotal: 99, min: 71, max: 75 },
{ part: 16, epart: 96, etotal: 99, min: 76, max: 80 },
{ part: 17, epart: 97, etotal: 100, min: 81, max: 85 },
{ part: 18, epart: 98, etotal: 100, min: 86, max: 90 },
{ part: 19, epart: 99, etotal: 100, min: 81, max: 95 },
{ part: 20, epart: 100, etotal: 100, min: 96, max: 100 }
];
const reussites = [
{ code: "etotal", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: true, isETotal: true, ptTache: -4, ptQualite: -6, quality: "Echec total", condition: (target, roll) => roll >= target.etotal && roll <= 100 },
{ code: "epart", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: true, isETotal: false, ptTache: -2, ptQualite: -4, quality: "Echec particulier", condition: (target, roll) => (roll >= target.epart && roll < target.etotal) },
{ code: "echec", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: false, isETotal: false, ptTache: 0, ptQualite: -2, quality: "Echec normal", condition: (target, roll) => (roll > target.score && roll < target.etotal) },
{ code: "norm", isPart: false, isSign: false, isSuccess: true, isEchec: false, isEPart: false, isETotal: false, ptTache: 1, ptQualite: 0, quality: "Réussite normale", condition: (target, roll) => (roll > target.sign && roll <= target.score) },
{ code: "sign", isPart: false, isSign: true, isSuccess: true, isEchec: false, isEPart: false, isETotal: false, ptTache: 2, ptQualite: 1, quality: "Réussite significative", condition: (target, roll) => (roll > target.part && roll <= target.sign) },
{ code: "part", isPart: true, isSign: true, isSuccess: true, isEchec: false, isEPart: false, isETotal: false, ptTache: 3, ptQualite: 2, quality: "Réussite Particulière!", condition: (target, roll) => (roll > 0 && roll <= target.part) },
{ code: "error", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: true, isETotal: true, ptTache: 0, ptQualite: 0, quality: "Jet de dés invalide", condition: (target, roll) => (roll <= 0 || roll > 100) }
];
/* -------------------------------------------- */
const reussiteSignificative = reussites.find(r => r.code == "sign");
const reussiteNormale = reussites.find(r => r.code == "norm");
const echecNormal = reussites.find(r => r.code == "echec");
const caracMaximumResolution = 60;
/* -------------------------------------------- */
export class RdDResolutionTable {
static resolutionTable = this.build()
/* -------------------------------------------- */
static build() {
let table = []
for (var caracValue = 0; caracValue <= caracMaximumResolution; caracValue++) {
table[caracValue] = this._computeRow(caracValue);
}
return table;
}
/* -------------------------------------------- */
static getResultat(code) {
let resultat = reussites.filter(r => code == r.code);
if (resultat == undefined) {
resultat = reussites.find(r => r.code == "error");
}
return resultat;
}
/* -------------------------------------------- */
static explain(rolled) {
let message = "<br>Jet : <strong>" + rolled.roll + "</strong> sur " + rolled.score + "% ";
if (rolled.caracValue != null && rolled.finalLevel!= null) {
message += "(" + rolled.caracValue + " à " + Misc.toSignedString(rolled.finalLevel) + ") ";
}
message += '<strong>' + rolled.quality + '</strong>'
return message;
}
/* -------------------------------------------- */
static updateChancesWithBonus( chances, bonus ) {
if (bonus) {
let newScore = Number(chances.score) + Number(bonus);
mergeObject(chances, this._computeCell(null, newScore), {overwrite: true});
}
}
/* -------------------------------------------- */
static async rollData(rollData ) {
rollData.rolled = await this.roll(rollData.caracValue, rollData.finalLevel, rollData.bonus);
}
/* -------------------------------------------- */
static async roll(caracValue, finalLevel, bonus = undefined ) {
let chances = this.computeChances(caracValue, finalLevel);
chances.showDice = true;
this.updateChancesWithBonus( chances, bonus);
let rolled = await this.rollChances(chances);
rolled.caracValue = caracValue;
rolled.finalLevel = finalLevel;
rolled.bonus = bonus;
return rolled;
}
/* -------------------------------------------- */
static async rollChances(chances) {
let myRoll = new Roll("1d100").roll();
myRoll.showDice = chances.showDice;
await RdDDice.show(myRoll);
chances.roll = myRoll.total;
mergeObject(chances, this._computeReussite(chances, chances.roll));
return chances;
}
/* -------------------------------------------- */
static computeChances(caracValue, difficulte) {
if (difficulte < -16) {
return duplicate(levelImpossible);
}
if (difficulte < -10) {
return duplicate(levelDown.find(levelData => levelData.level == difficulte));
}
return duplicate(this.resolutionTable[caracValue][difficulte + 10]);
}
/* -------------------------------------------- */
static buildXpMessage(rolled, level) {
if (rolled.isPart && level < 0) {
const xp = Math.abs(level);
const xpcarac = Math.floor(xp / 2);
const xpcomp = xp - xpcarac;
return "<br>Points d'expérience gagnés ! Carac: " + xpcarac + ", Comp: " + xpcomp;
}
return "";
}
/* -------------------------------------------- */
static _computeReussite(chances, roll) {
const reussite = reussites.find(x => x.condition(chances, roll));
if (chances.needSignificative) {
if (reussite.isSign) {
return reussiteNormale;
}
if (reussite.isSuccess) {
return echecNormal;
}
}
return reussite;
}
/* -------------------------------------------- */
static _computeRow(caracValue) {
let dataRow = [
this._computeCell(-10, Math.max(Math.floor(caracValue / 4), 1)),
this._computeCell(-9, Math.max(Math.floor(caracValue / 2), 1))
]
for (var diff = -8; diff <= 22; diff++) {
dataRow[diff + 10] = this._computeCell(diff, Math.max(Math.floor(caracValue * (diff + 10) / 2), 1));
}
return dataRow;
}
/* -------------------------------------------- */
static _computeCell(niveau, percentage) {
return {
niveau: niveau,
score: percentage,
sign: this._reussiteSignificative(percentage),
part: this._reussitePart(percentage),
epart: this._echecParticulier(percentage),
etotal: this._echecTotal(percentage)
}
}
/* -------------------------------------------- */
static _reussiteSignificative(score) {
return Math.floor(score / 2);
}
/* -------------------------------------------- */
static _reussitePart(score) {
return Math.ceil(score / 5);
}
/* -------------------------------------------- */
static _echecParticulier(score) {
return Math.ceil(score / 5) + 80;
}
/* -------------------------------------------- */
static _echecTotal(score) {
return Math.ceil(score / 10) + 91;
}
/* -------------------------------------------- */
static buildHTMLTableExtract(caracValue, levelValue) {
return this.buildHTMLTable(caracValue, levelValue, caracValue - 2, caracValue + 2, levelValue - 5, levelValue + 5)
}
static buildHTMLTable(caracValue, levelValue, minCarac = 1, maxCarac = 21, minLevel = -10, maxLevel = 11) {
return this._buildHTMLTable(caracValue, levelValue, minCarac, maxCarac, minLevel, maxLevel)
}
/* -------------------------------------------- */
static _buildHTMLTable(caracValue, levelValue, minCarac, maxCarac, minLevel, maxLevel) {
let countColonnes = maxLevel - minLevel;
minCarac = Math.max(minCarac, 1);
maxCarac = Math.min(maxCarac, caracMaximumResolution);
minLevel = Math.max(minLevel, -10);
maxLevel = Math.max(Math.min(maxLevel, 22), minLevel + countColonnes);
let table = $("<table class='table-resolution'/>")
.append(this._buildHTMLHeader(this.resolutionTable[0], minLevel, maxLevel));
for (var rowIndex = minCarac; rowIndex <= maxCarac; rowIndex++) {
table.append(this._buildHTMLRow(this.resolutionTable[rowIndex], rowIndex, caracValue, levelValue, minLevel, maxLevel));
}
return table;
}
/* -------------------------------------------- */
static _buildHTMLHeader(dataRow, minLevel, maxLevel) {
let tr = $("<tr/>");
if (minLevel > -8) {
tr.append($("<th class='table-resolution-level'/>").text("-8"))
}
if (minLevel > -7) {
tr.append($("<th class='table-resolution-level'/>").text("..."));
}
for (let difficulte = minLevel; difficulte <= maxLevel; difficulte++) {
tr.append($("<th class='table-resolution-level'/>").text(Misc.toSignedString(difficulte)));
}
return tr;
}
/* -------------------------------------------- */
static _buildHTMLRow(dataRow, rowIndex, caracValue, levelValue, minLevel, maxLevel) {
let tr = $("<tr/>");
let max = maxLevel;
if (minLevel > -8) {
let score = dataRow[-8 + 10].score;
tr.append($("<td class='table-resolution-carac'/>").text(score))
}
if (minLevel > -7) {
tr.append($("<td/>"))
}
for (let difficulte = minLevel; difficulte <= max; difficulte++) {
let td = $("<td/>");
let score = dataRow[difficulte + 10].score;
if (rowIndex == caracValue && levelValue == difficulte) {
td.addClass('table-resolution-target');
} else if (difficulte == -8) {
td.addClass('table-resolution-carac');
}
tr.append(td.text(score));
}
return tr;
}
}