2021-01-02 04:28:43 +01:00
import { ChatUtility } from "./chat-utility.js" ;
2020-11-15 02:07:41 +01:00
import { Misc } from "./misc.js" ;
2020-11-16 03:54:43 +01:00
import { RdDDice } from "./rdd-dice.js" ;
2022-11-06 21:39:03 +01:00
import { ReglesOptionelles } from "./settings/regles-optionelles.js" ;
2020-11-11 22:39:36 +01:00
2020-11-12 16:35:51 +01:00
/ * *
* difficultés au delà de - 10
* /
const levelDown = [
2021-10-30 02:20:16 +02:00
{ level : - 11 , score : 1 , norm : 1 , sign : 0 , part : 0 , epart : 2 , etotal : 90 } ,
{ level : - 12 , score : 1 , norm : 1 , sign : 0 , part : 0 , epart : 2 , etotal : 70 } ,
{ level : - 13 , score : 1 , norm : 1 , sign : 0 , part : 0 , epart : 2 , etotal : 50 } ,
{ level : - 14 , score : 1 , norm : 1 , sign : 0 , part : 0 , epart : 2 , etotal : 30 } ,
{ level : - 15 , score : 1 , norm : 1 , sign : 0 , part : 0 , epart : 2 , etotal : 10 } ,
{ level : - 16 , score : 1 , norm : 1 , sign : 0 , part : 0 , epart : 0 , etotal : 2 }
2020-11-12 16:35:51 +01:00
] ;
2022-12-06 01:30:12 +01:00
const levelImpossible = { score : 0 , norm : 0 , sign : 0 , part : 0 , epart : 0 , etotal : 1 } ;
2020-11-12 16:35:51 +01:00
const reussites = [
2020-12-12 21:58:44 +01:00
{ 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 ) } ,
2021-01-02 19:25:03 +01:00
{ 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 . norm && 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 . norm ) } ,
2020-12-12 21:58:44 +01:00
{ 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 ) }
2020-11-12 16:35:51 +01:00
] ;
2021-04-03 23:59:29 +02:00
const reussiteInsuffisante = { code : "notSign" , isPart : false , isSign : false , isSuccess : false , isEchec : true , isEPart : false , isETotal : false , ptTache : 0 , ptQualite : - 2 , quality : "Réussite insuffisante" , condition : ( target , roll ) => false }
2020-12-05 00:04:40 +01:00
/* -------------------------------------------- */
2020-12-06 23:31:23 +01:00
const caracMaximumResolution = 60 ;
2020-12-05 00:04:40 +01:00
/* -------------------------------------------- */
2020-11-11 22:39:36 +01:00
export class RdDResolutionTable {
static resolutionTable = this . build ( )
/* -------------------------------------------- */
static build ( ) {
let table = [ ]
2020-12-06 23:31:23 +01:00
for ( var caracValue = 0 ; caracValue <= caracMaximumResolution ; caracValue ++ ) {
2020-11-25 00:46:11 +01:00
table [ caracValue ] = this . _computeRow ( caracValue ) ;
2020-11-11 22:39:36 +01:00
}
return table ;
}
2022-12-06 01:30:12 +01:00
/* -------------------------------------------- */
static computeChances ( carac , level ) {
if ( level < - 16 ) {
return levelImpossible ;
}
if ( level < - 10 ) {
return levelDown . find ( it => it . level == level ) ;
}
const percentage = RdDResolutionTable . computePercentage ( carac , level ) ;
return this . _computeCell ( level , percentage ) ;
}
/* -------------------------------------------- */
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 , RdDResolutionTable . computePercentage ( caracValue , diff ) ) ;
}
return dataRow ;
}
/* -------------------------------------------- */
static _computeCell ( niveau , percentage ) {
return {
niveau : niveau ,
score : percentage ,
norm : Math . min ( 99 , percentage ) ,
sign : this . _reussiteSignificative ( percentage ) ,
part : this . _reussitePart ( percentage ) ,
epart : this . _echecParticulier ( percentage ) ,
etotal : this . _echecTotal ( percentage )
} ;
}
2020-11-15 16:38:45 +01:00
/* -------------------------------------------- */
2020-11-16 03:54:43 +01:00
static getResultat ( code ) {
2020-12-31 02:20:52 +01:00
let resultat = reussites . find ( r => code == r . code ) ;
2020-11-16 03:54:43 +01:00
if ( resultat == undefined ) {
2020-11-14 03:16:03 +01:00
resultat = reussites . find ( r => r . code == "error" ) ;
}
return resultat ;
}
2020-11-15 16:38:45 +01:00
2021-01-03 15:40:48 +01:00
/* -------------------------------------------- */
2021-01-05 18:43:13 +01:00
static async displayRollData ( rollData , actor = undefined , template = 'chat-resultat-general.html' ) {
2022-01-29 18:50:37 +01:00
return await ChatUtility . createChatWithRollMode ( actor ? . userName ? ? game . user . name , {
2021-01-09 19:36:19 +01:00
content : await RdDResolutionTable . buildRollDataHtml ( rollData , actor , template )
} ) ;
2020-12-31 02:08:58 +01:00
}
2021-01-05 18:43:13 +01:00
/* -------------------------------------------- */
static async buildRollDataHtml ( rollData , actor , template = 'chat-resultat-general.html' ) {
rollData . show = rollData . show || { } ;
return await renderTemplate ( ` systems/foundryvtt-reve-de-dragon/templates/ ${ template } ` , rollData ) ;
2020-11-12 16:35:51 +01:00
}
2020-12-04 20:52:04 +01:00
2020-11-15 16:38:45 +01:00
/* -------------------------------------------- */
2020-12-12 21:58:44 +01:00
static async rollData ( rollData ) {
2021-06-13 21:56:01 +02:00
rollData . rolled = await this . roll ( rollData . caracValue , rollData . finalLevel , rollData ) ;
2020-12-17 00:44:32 +01:00
return rollData ;
2020-12-06 19:29:10 +01:00
}
2020-12-08 23:07:41 +01:00
2020-12-04 20:52:04 +01:00
/* -------------------------------------------- */
2022-12-06 01:30:12 +01:00
static async roll ( caracValue , finalLevel , rollData = { } ) {
let chances = duplicate ( this . computeChances ( caracValue , finalLevel ) ) ;
2021-10-30 02:21:41 +02:00
this . _updateChancesWithBonus ( chances , rollData . bonus , finalLevel ) ;
2021-06-13 21:56:01 +02:00
this . _updateChancesFactor ( chances , rollData . diviseurSignificative ) ;
chances . showDice = rollData . showDice ;
chances . rollMode = rollData . rollMode ;
2020-12-12 21:58:44 +01:00
2021-06-28 20:19:02 +02:00
let rolled = await this . rollChances ( chances , rollData . diviseurSignificative , rollData . forceDiceResult ) ;
2020-11-25 00:46:11 +01:00
rolled . caracValue = caracValue ;
2020-11-16 03:54:43 +01:00
rolled . finalLevel = finalLevel ;
2021-06-13 21:56:01 +02:00
rolled . bonus = rollData . bonus ;
rolled . factorHtml = Misc . getFractionHtml ( rollData . diviseurSignificative ) ;
2021-10-09 22:02:13 +02:00
2022-12-06 01:30:12 +01:00
if ( ReglesOptionelles . isUsing ( "afficher-colonnes-reussite" ) ) {
2021-10-09 22:02:13 +02:00
rolled . niveauNecessaire = this . findNiveauNecessaire ( caracValue , rolled . roll ) ;
rolled . ajustementNecessaire = rolled . niveauNecessaire - finalLevel ;
}
2020-11-16 03:54:43 +01:00
return rolled ;
2020-11-15 16:38:45 +01:00
}
2020-11-12 16:35:51 +01:00
2021-05-28 09:12:18 +02:00
/* -------------------------------------------- */
2022-12-06 01:30:12 +01:00
static findNiveauNecessaire ( carac , rolled ) {
if ( carac == 0 ) {
return NaN ;
}
if ( rolled >= carac ) {
const upper = Math . ceil ( rolled / carac ) ;
return 2 * upper - 10
}
if ( rolled > Math . floor ( carac / 2 ) ) {
return - 8
}
if ( rolled > Math . floor ( carac / 4 ) ) {
return - 9
2021-05-28 09:12:18 +02:00
}
2022-12-06 01:30:12 +01:00
if ( rolled > 1 ) {
return - 10
}
return - 11 ;
2021-05-28 09:12:18 +02:00
}
2020-12-12 21:58:44 +01:00
/* -------------------------------------------- */
2021-01-02 04:28:43 +01:00
static _updateChancesFactor ( chances , diviseur ) {
2021-02-25 02:03:45 +01:00
if ( chances . level > - 11 && diviseur && diviseur > 1 ) {
2021-01-07 00:32:22 +01:00
let newScore = Math . floor ( chances . score / diviseur ) ;
2022-11-05 18:06:30 +01:00
mergeObject ( chances , this . _computeCell ( undefined , newScore ) , { overwrite : true } ) ;
2020-12-12 21:58:44 +01:00
}
}
/* -------------------------------------------- */
2021-10-30 02:21:41 +02:00
static _updateChancesWithBonus ( chances , bonus , finalLevel ) {
2022-12-06 01:30:12 +01:00
if ( bonus && finalLevel > - 11 ) {
2021-01-22 14:35:14 +01:00
let newScore = Number ( chances . score ) + bonus ;
2022-11-05 18:06:30 +01:00
mergeObject ( chances , this . _computeCell ( undefined , newScore ) , { overwrite : true } ) ;
2020-12-12 21:58:44 +01:00
}
}
2021-02-12 12:50:17 +01:00
2021-05-28 09:12:18 +02:00
/* -------------------------------------------- */
2021-01-23 18:36:30 +01:00
static significativeRequise ( chances ) {
2021-01-09 19:33:19 +01:00
chances . roll = Math . floor ( chances . score / 2 ) ;
2021-01-07 00:32:22 +01:00
mergeObject ( chances , reussites . find ( x => x . code == 'sign' ) , { overwrite : true } ) ;
}
2020-12-12 21:58:44 +01:00
2021-05-28 09:12:18 +02:00
/* -------------------------------------------- */
2021-02-12 12:50:17 +01:00
static succesRequis ( chances ) {
chances . roll = chances . score ;
mergeObject ( chances , reussites . find ( x => x . code == 'norm' ) , { overwrite : true } ) ;
}
2020-11-15 16:38:45 +01:00
/* -------------------------------------------- */
2021-06-28 20:19:02 +02:00
static async rollChances ( chances , diviseur , forceDiceResult = - 1 ) {
2022-12-06 01:30:12 +01:00
chances . forceDiceResult = forceDiceResult <= 0 || forceDiceResult > 100 ? undefined : { total : forceDiceResult } ;
chances . roll = await RdDDice . rollTotal ( "1d100" , chances ) ;
2021-04-03 23:59:29 +02:00
mergeObject ( chances , this . computeReussite ( chances , chances . roll , diviseur ) , { overwrite : true } ) ;
2020-11-12 16:35:51 +01:00
return chances ;
}
2020-11-15 16:38:45 +01:00
/* -------------------------------------------- */
2022-12-06 01:30:12 +01:00
static computePercentage ( carac , diff ) {
if ( diff < - 16 ) return 0
if ( diff < - 10 ) return 1
if ( diff == - 10 ) return Math . max ( Math . floor ( carac / 4 ) , 1 )
if ( diff == - 9 ) return Math . max ( Math . floor ( carac / 2 ) , 1 )
return Math . max ( Math . floor ( carac * ( diff + 10 ) / 2 ) , 1 ) ;
2020-11-12 16:35:51 +01:00
}
2021-01-04 22:03:00 +01:00
/* -------------------------------------------- */
2020-12-31 02:08:58 +01:00
static isAjustementAstrologique ( rollData ) {
2021-01-05 18:43:13 +01:00
if ( rollData . selectedCarac ? . label . toLowerCase ( ) . includes ( 'chance' ) ) {
2020-12-31 02:08:58 +01:00
return true ;
}
2022-09-07 09:01:23 +02:00
if ( rollData . selectedSort ? . system . isrituel ) {
2020-12-31 02:08:58 +01:00
return true ;
}
return false ;
}
2020-11-15 16:38:45 +01:00
/* -------------------------------------------- */
2020-12-12 21:58:44 +01:00
static isEchec ( rollData ) {
2020-12-15 02:20:24 +01:00
switch ( rollData . surprise ) {
case 'demi' : return ! rollData . rolled . isSign ;
case 'totale' : return true ;
}
return rollData . rolled . isEchec ;
2020-12-12 21:58:44 +01:00
}
2020-12-15 02:20:24 +01:00
2020-12-15 23:54:09 +01:00
/* -------------------------------------------- */
2020-12-12 21:58:44 +01:00
static isEchecTotal ( rollData ) {
2020-12-15 02:20:24 +01:00
if ( rollData . arme && rollData . surprise == 'demi' ) {
return rollData . rolled . isEchec ;
}
return rollData . rolled . isETotal ;
2020-12-12 21:58:44 +01:00
}
2020-12-18 23:48:41 +01:00
2020-12-15 23:54:09 +01:00
/* -------------------------------------------- */
2020-12-12 21:58:44 +01:00
static isParticuliere ( rollData ) {
2020-12-15 02:20:24 +01:00
if ( rollData . arme && rollData . surprise ) {
return false ;
}
return rollData . rolled . isPart ;
2020-12-12 21:58:44 +01:00
}
2020-12-15 02:20:24 +01:00
2020-12-15 23:54:09 +01:00
/* -------------------------------------------- */
2020-12-12 21:58:44 +01:00
static isReussite ( rollData ) {
2020-12-15 02:20:24 +01:00
switch ( rollData . surprise ) {
case 'demi' : return rollData . rolled . isSign ;
case 'totale' : return false ;
}
return rollData . rolled . isSuccess ;
2020-11-12 16:35:51 +01:00
}
/* -------------------------------------------- */
2021-04-03 23:59:29 +02:00
static computeReussite ( chances , roll , diviseur ) {
const reussite = reussites . find ( x => x . condition ( chances , roll ) ) ;
if ( diviseur > 1 && reussite . code == 'norm' ) {
return reussiteInsuffisante ;
}
return reussite ;
2020-11-12 16:35:51 +01:00
}
2020-11-16 23:28:18 +01:00
/* -------------------------------------------- */
2021-01-02 19:25:03 +01:00
static _reussiteSignificative ( percentage ) {
return Math . floor ( percentage / 2 ) ;
2020-11-11 22:39:36 +01:00
}
2020-11-16 23:28:18 +01:00
/* -------------------------------------------- */
2021-01-02 19:25:03 +01:00
static _reussitePart ( percentage ) {
return Math . ceil ( percentage / 5 ) ;
2020-11-11 22:39:36 +01:00
}
2020-11-16 23:28:18 +01:00
/* -------------------------------------------- */
2021-01-02 19:25:03 +01:00
static _echecParticulier ( percentage ) {
const epart = Math . ceil ( percentage / 5 ) + 80 ;
return epart >= 100 ? 101 : epart ;
2020-11-11 22:39:36 +01:00
}
2020-11-16 23:28:18 +01:00
/* -------------------------------------------- */
2021-01-02 19:25:03 +01:00
static _echecTotal ( percentage ) {
const etotal = Math . ceil ( percentage / 10 ) + 91 ;
return percentage >= 100 ? 101 : Math . min ( etotal , 100 ) ;
2020-11-11 22:39:36 +01:00
}
2020-12-15 23:54:09 +01:00
/* -------------------------------------------- */
2022-12-06 01:30:12 +01:00
static subTable ( carac , level , delta = { carac : 2 , level : 5 } ) {
return {
carac ,
level ,
minCarac : carac - ( delta ? . carac ? ? 2 ) ,
maxCarac : carac + ( delta ? . carac ? ? 2 ) ,
minLevel : level - ( delta ? . level ? ? 5 ) ,
maxLevel : level + ( delta ? . level ? ? 5 )
} ;
2020-11-11 22:39:36 +01:00
}
/* -------------------------------------------- */
2022-12-06 01:30:12 +01:00
static async buildHTMLTable ( { carac : carac , level : level , minCarac = 1 , maxCarac = 21 , minLevel = - 10 , maxLevel = 11 } ) {
let colonnes = maxLevel - minLevel ;
2020-11-11 22:39:36 +01:00
minCarac = Math . max ( minCarac , 1 ) ;
2022-12-06 01:30:12 +01:00
maxCarac = Math . min ( maxCarac , minCarac + 20 ) ;
2020-11-11 22:39:36 +01:00
minLevel = Math . max ( minLevel , - 10 ) ;
2022-12-06 01:30:12 +01:00
maxLevel = Math . max ( Math . min ( maxLevel , 30 ) , minLevel + colonnes ) ;
return await renderTemplate ( 'systems/foundryvtt-reve-de-dragon/templates/resolution-table.html' , {
carac : carac ,
difficulte : level ,
min : minLevel ,
rows : RdDResolutionTable . incrementalArray ( minCarac , maxCarac ) ,
cols : RdDResolutionTable . incrementalArray ( minLevel , maxLevel )
} ) ;
2020-11-11 22:39:36 +01:00
}
2022-12-06 01:30:12 +01:00
static incrementalArray ( min , max ) {
return Array . from ( Array ( max - min + 1 ) . keys ( ) ) . map ( i => i + min )
2020-11-11 22:39:36 +01:00
}
}