RdDResolutionTable rolls

This commit is contained in:
Vincent Vandemeulebrouck 2020-11-12 16:35:51 +01:00
parent 1fc3bf22f5
commit 5fa703241a
5 changed files with 277 additions and 263 deletions

View File

@ -7,6 +7,7 @@ import { RdDUtility } from "./rdd-utility.js";
import { TMRUtility } from "./tmr-utility.js"; import { TMRUtility } from "./tmr-utility.js";
import { RdDRollDialog } from "./rdd-roll-dialog.js"; import { RdDRollDialog } from "./rdd-roll-dialog.js";
import { RdDTMRDialog } from "./rdd-tmr-dialog.js"; import { RdDTMRDialog } from "./rdd-tmr-dialog.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
export class RdDActor extends Actor { export class RdDActor extends Actor {
@ -119,100 +120,62 @@ export class RdDActor extends Actor {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async performRoll( rollData ) { async performRoll(rollData) {
let result = new Roll("d100").roll().total;
let quality = "Echec";
let xpmsg = "";
let tache = 0;
//console.log(">>> ROLL", rollData.selectedCarac.label, rollData.rollTarget.score, myroll.total );
if (result <= rollData.rollTarget.part) {
quality = "Réussite Particulière!";
if ( rollData.finalLevel < 0 ) {
let xpcarac = Math.floor( Math.abs(rollData.finalLevel) / 2);
let xpcomp = (Math.abs(rollData.finalLevel) % 2 == 1) ? xpcarac+1 : xpcarac;
xpmsg = "<br>Points d'expérience gagné ! " + xpcarac + " - " + xpcomp;
}
rollData.pointsDeTache = 4;
rollData.qualite = 2;
} else if (result <= (rollData.rollTarget.score /2) ) {
quality = "Réussite Significative";
rollData.pointsDeTache = 2;
rollData.qualite = 1;
} else if (result <= (rollData.rollTarget.score) ) {
quality = "Réussite Normale";
rollData.pointsDeTache = 1;
rollData.qualite = 0;
} else if (result < (rollData.rollTarget.epart) ) {
quality = "Echec Normal";
rollData.pointsDeTache = 0;
rollData.qualite = -2;
} else if (result < (rollData.rollTarget.etotal) ) {
quality = "Echec Particulier";
rollData.pointsDeTache = -2;
rollData.qualite = -4;
} else if (result >= (rollData.rollTarget.etotal) ) {
quality = "Echec Total";
rollData.pointsDeTache = -4;
rollData.qualite = -6;
}
// Manage weapon categories when parrying (cf. page 115 ) // Manage weapon categories when parrying (cf. page 115 )
let need_significative = false; // Do we need to have a sgnificative ? let need_resist = false; // Do we need to make resistance roll for defender ?
let need_resist = false; // Do we need to have a sgnificative ? if (rollData.arme && rollData.attackerRoll) { // Manage parade depeding on weapon type, and change roll results
if ( rollData.arme && rollData.attackerRoll ) { // Manage parade depeding on weapon type, and change roll results let attCategory = RdDUtility.getArmeCategory(rollData.attackerRoll.arme);
let attCategory = RdDUtility.getArmeCategory( rollData.attackerRoll.arme ); let defCategory = RdDUtility.getArmeCategory(rollData.arme);
let defCategory = RdDUtility.getArmeCategory( rollData.arme ); if (defCategory == "bouclier")
if ( defCategory == "bouclier" ) rollData.needSignificative = true;
need_significative = true; else if (attCategory != defCategory)
else if ( attCategory != defCategory ) rollData.needSignificative = true;
need_significative = true; if (attCategory.match("epee") && (defCategory == "hache" || defCategory == "lance"))
if ( attCategory.match("epee") && ( defCategory == "hache" || defCategory == "lance") )
need_resist = true; need_resist = true;
} }
if (this.data.data.sante.sonne.value)
{
rollData.needSignificative = true;
}
// Sonne management or if need_significative is set let rolled = RdDResolutionTable.rollChances(rollData.rollTarget);
if ( this.data.data.sante.sonne.value || need_significative) { let result = rolled.roll;
if (rollData.pointsDeTache >= 2 ) { // Reussite normale dès que significative let quality = rolled.quality
quality = "Réussite Normale";
rollData.pointsDeTache = 1; console.log(">>> ROLL", rollData, rolled);
rollData.qualite = 0; let xpmsg = RdDResolutionTable.buildXpMessage(rolled, rollData.finalLevel);
} else if (rollData.pointsDeTache < 2 ) { // Not a "significative"
quality = "Echec Normal"; let specialStr = "<br>Points de taches : " + rolled.tache + ", Points de qualité: " + rolled.qualite;
rollData.pointsDeTache = 0;
rollData.qualite = -2;
}
}
// Fight management ! // Fight management !
let defenseMsg; let defenseMsg;
let encaisser = false; let encaisser = false;
let specialStr = "<br>Points de taches : " + rollData.pointsDeTache; // Per default if (rollData.arme) {
if ( rollData.arme ) { // In case of fight, replace the "tache" message per dommages + localization. "tache" indicates if result is OK or not // In case of fight, replace the message per dommages + localization. it indicates if result is OK or not
if ( rollData.attackerRoll) { // Defense case ! if (rollData.attackerRoll) { // Defense case !
if ( rollData.pointsDeTache > 0 ) { // Réussite ! if (rolled.isSuccess) {
specialStr = "<br><strong>Attaque parée/esquivée !</strong>"; specialStr = "<br><strong>Attaque parée/esquivée !</strong>";
} else { } else {
specialStr = "<br><strong>Esquive/Parade échouée, encaissement !</strong>"; specialStr = "<br><strong>Esquive/Parade échouée, encaissement !</strong>";
encaisser = true; encaisser = true;
} }
} else { // This is the attack roll! } else { // This is the attack roll!
if ( rollData.pointsDeTache > 0 ) { if (rolled.isSuccess > 0) {
let myroll = new Roll("2d10");
myroll.roll();
rollData.domArmePlusDom = parseInt(rollData.arme.data.dommages); rollData.domArmePlusDom = parseInt(rollData.arme.data.dommages);
if ( rollData.selectedCarac.label == "Mêlée" ) // +dom only for Melee if (rollData.selectedCarac.label == "Mêlée") // +dom only for Melee
rollData.domArmePlusDom += parseInt(this.data.data.attributs.plusdom.value); rollData.domArmePlusDom += parseInt(this.data.data.attributs.plusdom.value);
if ( rollData.selectedCarac.label == "Lancer" ) { // +dom only for Melee/Lancer if (rollData.selectedCarac.label == "Lancer") { // +dom only for Melee/Lancer
let bdom = parseInt(this.data.data.attributs.plusdom.value); let bdom = parseInt(this.data.data.attributs.plusdom.value);
if ( bdom > parseInt(rollData.arme.data.dommages)) if (bdom > parseInt(rollData.arme.data.dommages))
bdom = parseInt(rollData.arme.data.dommages); bdom = parseInt(rollData.arme.data.dommages);
rollData.domArmePlusDom += bdom rollData.domArmePlusDom += bdom
} }
rollData.degats = parseInt(myroll.result) + rollData.domArmePlusDom; let encaissement = new Roll("2d10 + @domArmePlusDom", {domArmePlusDom : rollData.domArmePlusDom});
rollData.degats = parseInt(encaissement.roll().total);
rollData.loc = RdDUtility.getLocalisation(); rollData.loc = RdDUtility.getLocalisation();
for (let target of game.user.targets) { for (let target of game.user.targets) {
defenseMsg = RdDUtility.buildDefenseChatCard(this, target, rollData ); defenseMsg = RdDUtility.buildDefenseChatCard(this, target, rollData);
specialStr = "<br><strong>Cible</strong> : " + target.actor.data.name; specialStr = "<br><strong>Cible</strong> : " + target.actor.data.name;
} }
specialStr += "<br>Dommages : " + rollData.degats + "<br>Localisation : " + rollData.loc.label; specialStr += "<br>Dommages : " + rollData.degats + "<br>Localisation : " + rollData.loc.label;
@ -224,35 +187,35 @@ export class RdDActor extends Actor {
// Sort management // Sort management
let lvl = "" let lvl = ""
if ( rollData.selectedSort) { // Lancement de sort ! if (rollData.selectedSort) { // Lancement de sort !
let draconic = rollData.selectedSort.data.draconic; let draconic = rollData.selectedSort.data.draconic;
specialStr = "<br>Lancement du sort <strong>" + rollData.selectedSort.name + "</strong> : " + draconic.charAt(0).toUpperCase() + draconic.slice(1) + "/" + rollData.selectedSort.data.difficulte + specialStr = "<br>Lancement du sort <strong>" + rollData.selectedSort.name + "</strong> : " + draconic.charAt(0).toUpperCase() + draconic.slice(1) + "/" + rollData.selectedSort.data.difficulte +
"/" + rollData.selectedSort.data.caseTMR + "/R" + rollData.selectedSort.data.ptreve; "/" + rollData.selectedSort.data.caseTMR + "/R" + rollData.selectedSort.data.ptreve;
specialStr += "<br>Depuis la case " + rollData.coord + " (" + TMRUtility.getTMRDescription(rollData.coord).label + ")"; specialStr += "<br>Depuis la case " + rollData.coord + " (" + TMRUtility.getTMRDescription(rollData.coord).label + ")";
lvl = rollData.selectedDraconic.name +"/"+ rollData.selectedSort.name; lvl = rollData.selectedDraconic.name + "/" + rollData.selectedSort.name;
let costReve = rollData.selectedSort.data.ptreve; let costReve = rollData.selectedSort.data.ptreve;
let myReve = duplicate(this.data.data.reve.reve); let myReve = duplicate(this.data.data.reve.reve);
if ( rollData.pointsDeTache > 0 ) { // Réussite du sort ! if (rollData.tache > 0) { // Réussite du sort !
if (rollData.pointsDeTache >= 4 ) costReve = Math.ceil(costReve/2); if (rollData.tache >= 4) costReve = Math.ceil(costReve / 2);
if (costReve < 1 ) costReve = 1; if (costReve < 1) costReve = 1;
myReve.value = myReve.value - costReve; // Todo 0 pts de reve !!!! myReve.value = myReve.value - costReve; // Todo 0 pts de reve !!!!
if (myReve.value < 0) myReve.value = 0; if (myReve.value < 0) myReve.value = 0;
await this.update( {"data.reve.reve": myReve } ); await this.update({ "data.reve.reve": myReve });
specialStr += "<br>Réussite du sort pour " + costReve + " Points de Rêve"; specialStr += "<br>Réussite du sort pour " + costReve + " Points de Rêve";
if ( !rollData.isSortReserve) { if (!rollData.isSortReserve) {
this.currentTMR.close(); // Close TMR ! this.currentTMR.close(); // Close TMR !
} else { // Mise en réserve } else { // Mise en réserve
let reserve = duplicate(this.data.data.reve.reserve); let reserve = duplicate(this.data.data.reve.reserve);
reserve.list.push( { coord: rollData.coord, sort: duplicate(rollData.selectedSort), draconic: duplicate(rollData.selectedDraconic) }); reserve.list.push({ coord: rollData.coord, sort: duplicate(rollData.selectedSort), draconic: duplicate(rollData.selectedDraconic) });
await this.update( {"data.reve.reserve": reserve} ); await this.update({ "data.reve.reserve": reserve });
this.currentTMR.updateSortReserve(); this.currentTMR.updateSortReserve();
} }
} else { } else {
if ( rollData.pointsDeTache == -4) { // Echec total ! if (rollData.tache == -4) { // Echec total !
costReve *= 2; costReve *= 2;
myReve.value = myReve.value - costReve; // Todo 0 pts de reve !!!! myReve.value = myReve.value - costReve; // Todo 0 pts de reve !!!!
if (myReve.value < 0) myReve.value = 0; if (myReve.value < 0) myReve.value = 0;
await this.update( {"data.reve.reve": myReve } ); await this.update({ "data.reve.reve": myReve });
specialStr += "<br><strong>Echec TOTAL</strong> du sort : " + costReve + " Points de Rêve"; specialStr += "<br><strong>Echec TOTAL</strong> du sort : " + costReve + " Points de Rêve";
} else { } else {
specialStr += "<br>Echec du sort !"; specialStr += "<br>Echec du sort !";
@ -260,7 +223,7 @@ export class RdDActor extends Actor {
this.currentTMR.close(); // Close TMR ! this.currentTMR.close(); // Close TMR !
} }
if (myReve.value == 0) { // 0 points de reve if (myReve.value == 0) { // 0 points de reve
ChatMessage.create( {title: "Zero Points de Reve !", content: this.name + " est réduit à 0 Points de Rêve, et tombe endormi !" } ); ChatMessage.create({ title: "Zero Points de Reve !", content: this.name + " est réduit à 0 Points de Rêve, et tombe endormi !" });
this.currentTMR.close(); // Close TMR ! this.currentTMR.close(); // Close TMR !
} }
} else { } else {
@ -268,36 +231,37 @@ export class RdDActor extends Actor {
} }
// Save it for fight in the flags area // Save it for fight in the flags area
await this.setFlag( 'world', 'rollData', null ); await this.setFlag('world', 'rollData', null);
await this.setFlag( 'world', 'rollData', rollData ); await this.setFlag('world', 'rollData', rollData);
// Final chat message // Final chat message
let chatOptions = { content: "<strong>Test : " + rollData.selectedCarac.label + " / " + lvl + "</strong><br>Jet : " + let chatOptions = {
rollData.selectedCarac.value + " / " + rollData.finalLevelStr + " -> " + rollData.rollTarget.score + "%<br><strong>Résutat : </strong>" + result + "<br>" + content: "<strong>Test : " + rollData.selectedCarac.label + " / " + lvl + "</strong><br>Jet : " +
rollData.selectedCarac.value + " / " + rollData.finalLevelStr + " -> " + rolled.score + "%<br><strong>Résutat : </strong>" + result + "<br>" +
"<strong>" + quality + "</strong>" + specialStr + xpmsg, "<strong>" + quality + "</strong>" + specialStr + xpmsg,
user: game.user._id, user: game.user._id,
title: "Résultat du test" title: "Résultat du test"
} }
ChatMessage.create( chatOptions ); ChatMessage.create(chatOptions);
// This an attack, generate the defense message // This an attack, generate the defense message
if ( defenseMsg ) { if (defenseMsg) {
if ( defenseMsg.toSocket) { if (defenseMsg.toSocket) {
game.socket.emit("system.foundryvtt-reve-de-dragon", { game.socket.emit("system.foundryvtt-reve-de-dragon", {
msg: "msg_defense", msg: "msg_defense",
data: defenseMsg data: defenseMsg
} ); });
} else { } else {
defenseMsg.whisper = [ game.user]; defenseMsg.whisper = [game.user];
ChatMessage.create( defenseMsg ); ChatMessage.create(defenseMsg);
} }
} }
// Get damages! // Get damages!
if ( encaisser ) { if (encaisser) {
this.encaisserDommages( rollData.attackerRoll ); this.encaisserDommages(rollData.attackerRoll);
}
} }
}
/* -------------------------------------------- */ /* -------------------------------------------- */
updateCarac( caracName, caracValue ) updateCarac( caracName, caracValue )
@ -637,60 +601,43 @@ export class RdDActor extends Actor {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async stressTest( ) { async stressTest() {
let target = RdDResolutionTable.computeChances(this.data.data.carac.reve.value, 0);
let stressRoll = this._stressRoll(target);
let compteurs = duplicate(this.data.data.compteurs); let compteurs = duplicate(this.data.data.compteurs);
let stress = compteurs.stress; let convertion = Math.floor(compteurs.stress.value * stressRoll.factor);
let xp = compteurs.experience;
let scoreTarget = RdDUtility.getResolutionField( this.data.data.carac.reve.value, 0 ); compteurs.experience.value += convertion;
scoreTarget.sig = Math.floor(scoreTarget.score / 2); compteurs.stress.value = Math.max(compteurs.stress.value - convertion - 1, 0);
let scoreValue = new Roll("d100").roll().total; ChatMessage.create({
let newXP = xp.value; title: "Jet de Stress", content: "Vous avez transformé " + convertion + " points de Stress en Expérience avec une réussite " + stressRoll.comment,
let factor = 0; whisper: ChatMessage.getWhisperRecipients(game.user.name)
let comment = "Echec Total (0%)" });
await this.update({ "data.compteurs": compteurs });
if (scoreValue <= scoreTarget.part ) {
scoreValue = new Roll("d100").roll().total;
if (scoreValue <= scoreTarget.sig) {
factor = 1.5;
comment = "Double Particulière (150%)"
} else {
factor = 1;
comment = "Particulière (100%)"
}
} else {
if ( scoreValue <= scoreTarget.sig ) {
factor = 0.75;
comment = "Significative (75%)"
} else {
if ( scoreValue <= scoreTarget.score ) {
factor = 0.5;
comment = "Normale (50%)"
} else if (scoreValue <= scoreTarget.epart) {
factor = 0.2;
comment = "Echec (20%)"
} else if (scoreValue <= scoreTarget.etotal) {
factor = 0.1;
comment = "Echec (10%)"
}
}
} }
let xpValue = Math.floor(stress.value * factor); _stressRoll(target) {
stress.value -= xpValue; let result = RdDResolutionTable.rollChances(target)
stress.value -= 1; switch (result.quality) {
if (stress.value < 0 ) stress.value = 0; case "sign": return { factor: 0.75, comment: "Significative (75%) - " + result.roll }
case "norm": return { factor: 0.5, comment: "Normale (50%) - " + result.roll }
ChatMessage.create( { title: "Jet de Stress", content: "Vous avez transformé "+ xpValue + " points de Stress en Expérience avec une réussite " + comment , case "echec": return { factor: 0.2, comment: "Echec (20%) - " + result.roll }
whisper: ChatMessage.getWhisperRecipients(game.user.name) } ); case "epart": return { factor: 0.1, comment: "Echec particulier(10%) - " + result.roll }
case "etotal": return { factor: 0, comment: "Echec Total (0%) - " + result.roll }
xp.value += xpValue; }
await this.update( { "data.compteurs": compteurs } ); let second = RdDResolutionTable.rollChances(target)
switch (second.qualite) {
case "part": case "sign":
return { factor: 1.5, comment: "Double Particulière (150%) - " + result + " puis " + second }
default:
return { factor: 1, comment: "Particulière (100%) - " + result + " puis " + second }
}
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollUnSort( coord ) { async rollUnSort(coord) {
let draconicList = this.getDraconicList(); let draconicList = this.getDraconicList();
let sortList = this.getSortList(); let sortList = this.getSortList();

View File

@ -1,4 +1,58 @@
/**
* 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, isEPart: true, isETotal: true, tache: -4, qualite: -6, quality: "Echec total", condition: (target, roll) => roll >= target.etotal && roll <= 100 },
{ code: "epart", isPart: false, isSign: false, isSuccess: false, isEPart: true, isETotal: false, tache: -2, qualite: -4, quality: "Echec particulier", condition: (target, roll) => (roll >= target.epart && roll < target.etotal) },
{ code: "echec", isPart: false, isSign: false, isSuccess: false, isEPart: false, isETotal: false, tache: 0, qualite: -2, quality: "Echec normal", condition: (target, roll) => (roll > target.score && roll < target.etotal) },
{ code: "norm", isPart: false, isSign: false, isSuccess: true, isEPart: false, isETotal: false, tache: 1, qualite: 0, quality: "Réussite normale", condition: (target, roll) => (roll > target.sign && roll <= target.score) },
{ code: "sign", isPart: false, isSign: true, isSuccess: true, isEPart: false, isETotal: false, tache: 2, qualite: 1, quality: "Réussite significative", condition: (target, roll) => (roll > target.part && roll <= target.sign) },
{ code: "part", isPart: true, isSign: true, isSuccess: true, isEPart: false, isETotal: false, tache: 3, qualite: 2, quality: "Réussite Particulière!", condition: (target, roll) => (roll > 0 && roll <= target.part) },
{ code: "error", isPart: false, isSign: false, isSuccess: false, isEPart: true, isETotal: true, tache: 0, qualite: 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");
export class RdDResolutionTable { export class RdDResolutionTable {
static resolutionTable = this.build() static resolutionTable = this.build()
@ -12,25 +66,71 @@ export class RdDResolutionTable {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static roll(carac, difficulte) {
return this.rollChances(this.computeChances(carac, difficulte));
}
static rollChances(chances) {
chances.roll = new Roll("d100").roll().total;
mergeObject(chances, this._computeReussite(chances, chances.roll));
return chances;
}
static computeChances(carac, difficulte) {
if (difficulte < -16) {
return duplicate(levelImpossible);
}
if (difficulte < -10) {
return duplicate(levelDown.find(levelData => levelData.level == difficulte));
}
return duplicate(this.resolutionTable[carac][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(carac) { static _computeRow(carac) {
let dataRow = [ let dataRow = [
this._computeScore(-10, Math.max(Math.floor(carac / 4), 1)), this._computeCell(-10, Math.max(Math.floor(carac / 4), 1)),
this._computeScore(-9, Math.max(Math.floor(carac / 2), 1)) this._computeCell(-9, Math.max(Math.floor(carac / 2), 1))
] ]
for (var diff = -8; diff <= 22; diff++) { for (var diff = -8; diff <= 22; diff++) {
dataRow[diff + 10] = this._computeScore(diff, Math.max(Math.floor(carac * (diff + 10) / 2), 1)); dataRow[diff + 10] = this._computeCell(diff, Math.max(Math.floor(carac * (diff + 10) / 2), 1));
} }
return dataRow; return dataRow;
} }
static _computeScore(diff, score) { static _computeCell(niveau, percentage) {
return { return {
niveau: diff, niveau: niveau,
score: score, score: percentage,
sign: this._reussiteSignificative(score), sign: this._reussiteSignificative(percentage),
part: this._reussitePart(score), part: this._reussitePart(percentage),
epart: this._echecParticulier(score), epart: this._echecParticulier(percentage),
etotal: this._echecTotal(score) etotal: this._echecTotal(percentage)
} }
} }

View File

@ -1,5 +1,4 @@
import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDUtility } from "./rdd-utility.js";
/** /**
* Extend the base Dialog entity by defining a custom window to perform roll. * Extend the base Dialog entity by defining a custom window to perform roll.
@ -67,7 +66,7 @@ export class RdDRollDialog extends Dialog {
rollData.finalLevel = rollLevel; rollData.finalLevel = rollLevel;
rollData.finalLevelStr = (rollLevel > 0 ? "+" : "") + rollLevel; rollData.finalLevelStr = (rollLevel > 0 ? "+" : "") + rollLevel;
rollData.rollTarget = RdDUtility.getResolutionField(rollData.selectedCarac.value, rollData.finalLevel); rollData.rollTarget = RdDResolutionTable.computeChances(rollData.selectedCarac.value, rollData.finalLevel);
$("#roll-param").text(rollData.selectedCarac.value + " / " + rollData.finalLevelStr); $("#roll-param").text(rollData.selectedCarac.value + " / " + rollData.finalLevelStr);
$("#compdialogTitle").text(RdDRollDialog._getTitle(rollData)); $("#compdialogTitle").text(RdDRollDialog._getTitle(rollData));
@ -80,7 +79,8 @@ export class RdDRollDialog extends Dialog {
// Update html, according to data // Update html, according to data
if (rollData.competence) { if (rollData.competence) {
// Set the default carac from the competence item // Set the default carac from the competence item
console.log(rollData.competence.data.defaut_carac, rollData.carac); console.log("RdDDialogRoll", rollData.competence.data.defaut_carac, rollData.carac);
rollData.selectedCarac = rollData.carac[rollData.competence.data.defaut_carac]; rollData.selectedCarac = rollData.carac[rollData.competence.data.defaut_carac];
$("#carac").val(rollData.competence.data.defaut_carac); $("#carac").val(rollData.competence.data.defaut_carac);
} }
@ -91,30 +91,32 @@ export class RdDRollDialog extends Dialog {
// Update ! // Update !
html.find('#bonusmalus').click((event) => { html.find('#bonusmalus').click((event) => {
rollData.bmValue = event.currentTarget.value; // Update the selected bonus/malus rollData.bmValue = event.currentTarget.value; // Update the selected bonus/malus
//console.log("BM CLICKED !!!", rollData.bmValue, rollData.competence.data.niveau, parseInt(rollData.competence.data.niveau) + parseInt(rollData.bmValue) ); console.debug("RdDRollDialog","BM CLICKED !!!", rollData.bmValue, rollData.competence.data.niveau, parseInt(rollData.competence.data.niveau) + parseInt(rollData.bmValue) );
updateRollResult(rollData); updateRollResult(rollData);
}); });
html.find('#carac').click((event) => { html.find('#carac').click((event) => {
let caracKey = event.currentTarget.value; let caracKey = event.currentTarget.value;
rollData.selectedCarac = rollData.carac[caracKey]; // Update the selectedCarac rollData.selectedCarac = rollData.carac[caracKey]; // Update the selectedCarac
//console.log("CARAC CLICKED !!!", rollData.selectedCarac, rollData.competence.data.niveau, rollData.bmValue); console.debug("RdDRollDialog","CARAC CLICKED !!!", rollData.selectedCarac, rollData.competence.data.niveau, rollData.bmValue);
updateRollResult(rollData); updateRollResult(rollData);
}); });
html.find('#draconic').click((event) => { html.find('#draconic').click((event) => {
let draconicKey = event.currentTarget.value; let draconicKey = event.currentTarget.value;
rollData.selectedDraconic = rollData.draconicList[draconicKey]; // Update the selectedCarac rollData.selectedDraconic = rollData.draconicList[draconicKey]; // Update the selectedCarac
//console.log("CARAC CLICKED !!!", rollData.selectedCarac, rollData.competence.data.niveau, rollData.bmValue); console.debug("RdDRollDialog","CARAC CLICKED !!!", rollData.selectedCarac, rollData.competence.data.niveau, rollData.bmValue);
updateRollResult(rollData); updateRollResult(rollData);
}); });
html.find('#sort').click((event) => { html.find('#sort').click((event) => {
let sortKey = event.currentTarget.value; let sortKey = event.currentTarget.value;
rollData.selectedSort = rollData.sortList[sortKey]; // Update the selectedCarac rollData.selectedSort = rollData.sortList[sortKey]; // Update the selectedCarac
//console.log("CARAC CLICKED !!!", rollData.selectedCarac, rollData.competence.data.niveau, rollData.bmValue); console.debug("RdDRollDialog","CARAC CLICKED !!!", rollData.selectedCarac, rollData.competence.data.niveau, rollData.bmValue);
updateRollResult(rollData); updateRollResult(rollData);
}); });
} }
/* -------------------------------------------- */
static _computeFinalLevel(rollData) { static _computeFinalLevel(rollData) {
let etat = rollData.etat === undefined ? 0 : parseInt(rollData.etat); let etat = rollData.etat === undefined ? 0 : parseInt(rollData.etat);
if (rollData.competence) { if (rollData.competence) {

View File

@ -5,6 +5,7 @@
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { TMRUtility } from "./tmr-utility.js"; import { TMRUtility } from "./tmr-utility.js";
import { RdDRollTables } from "./rdd-rolltables.js"; import { RdDRollTables } from "./rdd-rolltables.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
/** Helper functions */ /** Helper functions */
export class RdDTMRDialog extends Dialog { export class RdDTMRDialog extends Dialog {
@ -130,13 +131,14 @@ export class RdDTMRDialog extends Dialog {
this.actor.deleteTMRRencontreAtPosition( ); // Remove the stored rencontre if necessary this.actor.deleteTMRRencontreAtPosition( ); // Remove the stored rencontre if necessary
this.updatePreviousRencontres(); this.updatePreviousRencontres();
let draconic = this.actor.getBestDraconic(); const draconic = this.actor.getBestDraconic();
let carac = this.actor.getCurrentReve(); const carac = this.actor.getCurrentReve();
let level = draconic.data.niveau - this.currentRencontre.force; const difficulte = draconic.data.niveau - this.currentRencontre.force;
console.log("Maitriser", carac, draconic.data.niveau, this.currentRencontre.force); console.log("Maitriser", carac, draconic.data.niveau, this.currentRencontre.force);
let scoreDef = CONFIG.RDD.resolutionTable[carac][level+10];
let result = new Roll("d100").roll().total; const roll = RdDResolutionTable.roll(carac, difficulte);
if ( result > scoreDef.score ) {
if ( roll.roll > scoreDef.score ) {
TMRUtility.processRencontreEchec( this.actor, this.currentRencontre); TMRUtility.processRencontreEchec( this.actor, this.currentRencontre);
ChatMessage.create( { title: "TMR", content: "Vous avez <strong>échoué</strong> à votre maîtrise d'un " . this.currentRencontre.name + " de force " + ChatMessage.create( { title: "TMR", content: "Vous avez <strong>échoué</strong> à votre maîtrise d'un " . this.currentRencontre.name + " de force " +
this.currentRencontre.force + this.currentRencontre.force +
@ -233,39 +235,42 @@ export class RdDTMRDialog extends Dialog {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async manageCaseHumide( cellDescr ) { async manageCaseHumide(cellDescr) {
if ( cellDescr.type == "lac" || cellDescr.type == "fleuve" || cellDescr.type == "marais" ) { if (cellDescr.type == "lac" || cellDescr.type == "fleuve" || cellDescr.type == "marais") {
let draconic = this.actor.getBestDraconic(); let draconic = this.actor.getBestDraconic();
let carac = this.actor.getCurrentReve(); let carac = this.actor.getCurrentReve();
let level = draconic.data.niveau - 7; let level = draconic.data.niveau - 7;
let scoreDef = CONFIG.RDD.resolutionTable[carac][level+10]; let rolled = RdDResolutionTable.roll(carac, level);//RdDResolutionTable.computeChances(carac, level);
let result = new Roll("d100").roll().total;
console.log(">>>>", rolled);
this.toclose = rolled.isSuccess;
let content = ""; let content = "";
let mycallback; if (!rolled.isSuccess) {
console.log(">>>>", scoreDef); content += "Vous êtes entré sur une case humide, et vous avez <strong>raté</strong> votre maîtrise ! Vous <strong>quittez les Terres Médianes</strong> !"
if ( result > scoreDef.score ) { }
content = "Vous êtes entré sur une case humide, et vous avez <strong>raté</strong> votre maîtrise ! Vous <strong>quittez les Terres Médianes</strong> ! ("+ draconic.name +") :" + carac + " / " + level + " -> " + result + " / " + scoreDef.score; else {
if ( result >= scoreDef.etotal ) { content += "Vous êtes entré sur une case humide, et vous avez <strong>réussi</strong> votre maîtrise !"
}
content += " " + draconic.name + ": " + carac + " / " + level + " -> " + rolled.roll + " / " + rolled.score;
if (rolled.isETotal) {
let souffle = RdDRollTables.getSouffle(true); let souffle = RdDRollTables.getSouffle(true);
content += "<br>Vous avez fait un Echec Total. Vous subissez un Souffle de Dragon : " + souffle.name ; content += "<br>Vous avez fait un Echec Total. Vous subissez un Souffle de Dragon : " + souffle.name;
this.actor.createOwnedItem( souffle ); this.actor.createOwnedItem(souffle);
} }
this.toclose = true; if (rolled.isPart) {
} else {
content = "Vous êtes entré sur une case humide, et vous avez <strong>réussi</strong> votre maîtrise ! ("+ draconic.name +") :" + carac + " / " + level + " -> " + result + " / " + scoreDef.score;
if ( result <= scoreDef.part ) {
content += "<br>Vous avez fait une Réussite Particulière"; content += "<br>Vous avez fait une Réussite Particulière";
if ( level < 0 ) { content += RdDResolutionTable.buildXpMessage(rolled, level)
let xpcarac = Math.floor( Math.abs(level) / 2);
let xpcomp = (Math.abs(level) % 2 == 1) ? xpcarac+1 : xpcarac;
content += "<br>Points d'expérience gagné ! " + xpcarac + " - " + xpcomp;
} }
}
} let humideDiag = new Dialog({
let humideDiag = new Dialog( {title: "Case humide", title: "Case humide",
content: content, content: content,
buttons: { buttons: {
choice: { icon: '<i class="fas fa-check"></i>', choice: {
icon: '<i class="fas fa-check"></i>',
label: "Fermer", label: "Fermer",
callback: () => this.manageCaseHumideResult() callback: () => this.manageCaseHumideResult()
} }

View File

@ -22,39 +22,11 @@ const competence_xp = {
"-6" : [ 10, 20, 35, 50, 65, 80, 100, 120, 140], "-6" : [ 10, 20, 35, 50, 65, 80, 100, 120, 140],
"-4" : [ 15, 30, 45, 60, 80, 100, 120] "-4" : [ 15, 30, 45, 60, 80, 100, 120]
} }
// This table starts at 0 -> niveau -10 // This table starts at 0 -> niveau -10
const competence_xp_par_niveau = [ 5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20, 30, 30, 40, 40, 60, 60, 100, 100, 100, 100, 100, 100, 100, 100, 100]; const competence_xp_par_niveau = [ 5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20, 30, 30, 40, 40, 60, 60, 100, 100, 100, 100, 100, 100, 100, 100, 100];
const carac_array = [ "taille", "apparence", "constitution", "force", "agilite", "dexterite", "vue", "ouie", "odoratgout", "volonte", "intellect", "empathie", "reve", "chance", "melee", "tir", "lancer", "derobee"]; const carac_array = [ "taille", "apparence", "constitution", "force", "agilite", "dexterite", "vue", "ouie", "odoratgout", "volonte", "intellect", "empathie", "reve", "chance", "melee", "tir", "lancer", "derobee"];
const bonusmalus = [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10]; const bonusmalus = [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10];
const specialResults = [ { "part": 0, "epart": 0, "etotal": 0 }, // 0
{ "part": 1, "epart": 81, "etotal": 92 }, // 01-05
{ "part": 2, "epart": 82, "etotal": 92 }, // 06-10
{ "part": 3, "epart": 83, "etotal": 93 }, // 11-15
{ "part": 4, "epart": 84, "etotal": 93 }, // 16-20
{ "part": 5, "epart": 85, "etotal": 94 }, // 21-25
{ "part": 6, "epart": 86, "etotal": 94 }, // 26-30
{ "part": 7, "epart": 87, "etotal": 95 }, // 31-35
{ "part": 8, "epart": 88, "etotal": 95 }, // 36-40
{ "part": 9, "epart": 89, "etotal": 96 }, // 41-45
{ "part": 10, "epart": 90, "etotal": 96 }, // 46-50
{ "part": 11, "epart": 91, "etotal": 97 }, // 51-55
{ "part": 12, "epart": 92, "etotal": 97 }, // 56-60
{ "part": 13, "epart": 93, "etotal": 98 }, // 61-65
{ "part": 14, "epart": 94, "etotal": 98 }, // 65-70
{ "part": 15, "epart": 95, "etotal": 99 }, // 71-75
{ "part": 16, "epart": 96, "etotal": 99 }, // 76-80
{ "part": 17, "epart": 97, "etotal": 100 }, // 81-85
{ "part": 18, "epart": 98, "etotal": 100 }, // 86-90
{ "part": 19, "epart": 99, "etotal": 100 }, // 81-95
{ "part": 20, "epart": 100, "etotal": 100 } // 96-00
];
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": 2, "etotal": 2 }
];
const fatigueMatrix = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // Dummy filler for the array. const fatigueMatrix = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // Dummy filler for the array.
[2, 3, 3, 2, 3, 3, 2, 3, 3, 2, 3, 3 ], [2, 3, 3, 2, 3, 3, 2, 3, 3, 2, 3, 3 ],
[2, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3 ], [2, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3 ],
@ -239,18 +211,6 @@ export class RdDUtility {
return false; return false;
} }
/* -------------------------------------------- */
static getResolutionField(caracValue, levelValue )
{
if ( levelValue < -16 ) {
return { score: 0, sign:0, part: 0, epart: 1, etotal: 1};
}
if ( levelValue < -10 ) {
return levelDown.find(levelData => levelData.level == levelValue);
}
return CONFIG.RDD.resolutionTable[caracValue][levelValue+10];
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static computeCompetenceXPCost( competence ) static computeCompetenceXPCost( competence )
{ {