Merge branch 'ajustements-tooltips' into 'v1.2'

Gestion des ajustements unifiée

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!103
This commit is contained in:
Leratier Bretonnien 2021-01-06 08:07:13 +00:00
commit 92fc7eac48
30 changed files with 532 additions and 376 deletions

View File

@ -161,38 +161,56 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
getReveActuel() {
return this.data.data.reve.reve.value;
return this.data.data.reve?.reve?.value ?? this.data.data.carac.reve.value;
}
getChanceActuel() {
return this.data.data.compteurs.chance.value;
return this.data.data.compteurs.chance?.value ?? 10;
}
/* -------------------------------------------- */
getForceValue() {
return this.data.data.carac.force ? this.data.data.carac.force.value : this.data.data.carac.reve.value;
return this.data.data.carac.force?.force ?? this.data.data.carac.reve.value;
}
getMoralTotal() {
return this.data.data.compteurs.moral?.value ?? 0;
}
/* -------------------------------------------- */
getBonusDegat() {
// TODO: gérer séparation et +dom créature/entité indépendament de la compétence
return Misc.toInt(this.data.data.attributs.plusdom.value);
}
/* -------------------------------------------- */
getProtectionNaturelle() {
return Misc.toInt(this.data.data.attributs.protection.value);
}
getEtatGeneral() {
return this.data.data.compteurs.etat.value;
}
getMalusArmure() {
return this.data.data.attributs?.malusarmure?.value ?? 0;
}
getEncTotal() {
return Math.floor(this.encTotal ?? 0);
}
getSurenc(){
return this.data.data.compteurs?.surenc?.value ?? 0;
}
/* -------------------------------------------- */
getCompetenceList() {
return this.data.items.filter( (item) => item.type == 'competence');
}
/* -------------------------------------------- */
getCompetence(compName) {
return RdDUtility.findCompetence(this.data.items, compName);
}
/* -------------------------------------------- */
getTache( id ) {
return this.data.items.find( item => item.type=='tache' && item._id == id );
}
getMeditation( id ) {
return this.data.items.find( item => item.type=='meditation' && item._id == id );
}
/* -------------------------------------------- */
getBestDraconic() {
const list = this.getDraconicList().sort((a, b) => b.data.niveau - a.data.niveau);
@ -203,10 +221,6 @@ export class RdDActor extends Actor {
return duplicate(list[0]);
}
getEncombrementTotal() {
return this.encTotal ? Math.floor(this.encTotal) : 0
}
/* -------------------------------------------- */
async deleteSortReserve(sortReserve) {
let reserve = duplicate(this.data.data.reve.reserve);
@ -223,11 +237,6 @@ export class RdDActor extends Actor {
}
}
/* -------------------------------------------- */
getDiviseurSignificative() {
return this.getSurprise() == 'demi' ? 2 : 1;
}
/* -------------------------------------------- */
getSurprise() {
if (this.isEntiteCauchemar()) {
@ -502,7 +511,7 @@ export class RdDActor extends Actor {
async combattreReveDeDragon(force){
let draconic = this.getBestDraconic();
let niveau = Math.max(0, draconic.data.niveau);
let etat = this.data.data.compteurs.etat.value;
let etat = this.getEtatGeneral();
let difficulte = niveau - etat - force;
let reveActuel = this.getReveActuel();
let rolled = await RdDResolutionTable.roll(reveActuel, difficulte);
@ -700,13 +709,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
detectSurEncombrement( ) {
let diffEnc = Number(this.encTotal) - Number(this.data.data.attributs.encombrement.value);
if ( diffEnc > 0 ) { // Sur-encombrement
let malus = Math.round( diffEnc);
malus = (malus == 0) ? 1 : malus; // Always 1 at least
//console.log("Sur enc malus", malus);
return malus;
}
return 0;
return Math.max(0, Math.ceil(diffEnc));
}
/* -------------------------------------------- */
@ -770,7 +773,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
getEtatGeneral() {
return (this.data.data.compteurs && this.data.data.compteurs.etat) ? this.data.data.compteurs.etat.value : 0;
return this.data.data.compteurs?.etat?.value ?? 0;
}
/* -------------------------------------------- */
@ -784,11 +787,13 @@ export class RdDActor extends Actor {
}
// Pour les autres
let state = - (data.sante.vie.max - data.sante.vie.value);
if (data.sante.fatigue) // Creatures n'ont pas de fatigue
if (data.sante.fatigue){
// Creatures n'ont pas de fatigue
state += RdDUtility.currentFatigueMalus(data.sante.fatigue.value, data.sante.endurance.max);
if (data.compteurs && data.compteurs.ethylisme && data.compteurs.ethylisme.value < 0 ) { // Ajout de l'éthylisme
state += data.compteurs.ethylisme.value;
}
// Ajout de l'éthylisme
state += Math.min(0, (data.compteurs?.ethylisme?.value ??0));
data.compteurs.etat.value = state;
if ( data.compteurs && data.compteurs.surenc) {
data.compteurs.surenc.value = - this.detectSurEncombrement();
@ -1230,7 +1235,7 @@ export class RdDActor extends Actor {
async ethylismeTest() {
let rollData = {
vieValue: this.data.data.sante.vie.value,
etat: this.data.data.compteurs.etat.value - Math.min(0, this.data.data.compteurs.ethylisme.value), // Pour les jets d'Ethylisme, on ignore le degré d'éthylisme (p.162)
etat: this.getEtatGeneral() - Math.min(0, this.data.data.compteurs.ethylisme.value), // Pour les jets d'Ethylisme, on ignore le degré d'éthylisme (p.162)
diffNbDoses: -Number(this.data.data.compteurs.ethylisme.nb_doses || 0),
finalLevel: 0,
diffConditions: 0,
@ -1423,6 +1428,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async _appliquerAjoutExperience(rollData, display=true) {
if (!this.isPersonnage()) return;
let xpResult = this.appliquerExperience( rollData.rolled, rollData.selectedCarac.label, rollData.competence);
if (display && xpResult.result ) {
let xpmsg = "<br>Points d'expérience gagnés ! Carac: " + xpResult.xpCarac + ", Comp: " + xpResult.xpCompetence;
@ -1634,7 +1640,7 @@ export class RdDActor extends Actor {
this.currentTMR.maximize(); // Re-display TMR
}
// Final chat message
await RdDResolutionTable.displayRollData(rollData, this.name, 'chat-resultat-sort.html');
RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-sort.html');
if (myReve.value == 0) { // 0 points de reve
ChatMessage.create({ content: this.name + " est réduit à 0 Points de Rêve, et tombe endormi !" });
@ -1653,7 +1659,7 @@ export class RdDActor extends Actor {
label: 'Jet ' + Grammar.apostrophe('de', rollData.selectedCarac.label),
callbacks: [
this.createCallbackExperience(),
{ action: this._onRollCaracResult }
{ action: r => this._onRollCaracResult(r) }
]
}
);
@ -1663,7 +1669,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async _onRollCaracResult(rollData) {
// Final chat message
await RdDResolutionTable.displayRollData(rollData, this.name, 'chat-resultat-general.html');
RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-general.html');
}
/* -------------------------------------------- */
@ -1684,7 +1690,7 @@ export class RdDActor extends Actor {
label: 'Jet ' +Grammar.apostrophe('de', name),
callbacks: [
this.createCallbackExperience(),
{ action: this._competenceResult }
{ action: r => this._competenceResult(r) }
]
} );
dialog.render(true);
@ -1708,11 +1714,6 @@ export class RdDActor extends Actor {
await this.createOwnedItem( tache, { renderSheet: true } );
}
/* -------------------------------------------- */
getTacheMeditation ( id ) {
return this.data.items.find( item => item._id == id );
}
/* -------------------------------------------- */
async rollTache( id ) {
let tache = duplicate( this.getTache( id ) );
@ -1749,7 +1750,7 @@ export class RdDActor extends Actor {
this.updateEmbeddedEntity( "OwnedItem", rollData.tache);
this.santeIncDec( "fatigue", rollData.tache.data.fatigue);
RdDResolutionTable.displayRollData(rollData, this.name, 'chat-resultat-tache.html');
RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-tache.html');
}
/* -------------------------------------------- */
@ -1760,24 +1761,26 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async rollMeditation( id ) {
let meditation = duplicate( this.getTacheMeditation( id ) );
let meditation = duplicate(this.getMeditation(id));
let competence = duplicate(this.getCompetence(meditation.data.competence));
competence.data.defaut_carac = "intellect"; // Meditation = tjs avec intellect
let meditationData = {
competence: competence,
competence: competence,
meditation: meditation,
conditionMeditation: {
isHeure: false,
isVeture: false,
isComportement: false,
isPurification: false,
},
diffConditions: 0,
editLibre: false,
editConditions: true,
isHeure: false,
isVeture: false,
isComportement: false,
isPurification: false,
carac : { }
};
meditationData.carac["intellect"] = duplicate(this.data.data.carac["intellect"]);
console.log("rollMedittion !!!", meditationData);
console.log("rollMeditation !!!", meditationData);
const dialog = await RdDRoll.create(this, meditationData, {html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-meditation.html'}, {
name: 'jet-meditation',
@ -1805,7 +1808,6 @@ export class RdDActor extends Actor {
RdDResolutionTable.displayRollData(meditationData, this.name, 'chat-resultat-meditation.html');
}
/* -------------------------------------------- */
_meditationETotal(meditationData) {
meditationData.meditation.data.malus--;
@ -1814,14 +1816,13 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async _competenceResult(rollData) {
RdDResolutionTable.displayRollData(rollData, this.name, 'chat-resultat-competence.html')
RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-competence.html')
}
/* -------------------------------------------- */
async rollAppelChance( )
{
let rollData = { selectedCarac: this.getCaracByName('chance-actuelle'), surprise: '' };
const dialog = await RdDRoll.create(this, rollData,
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-carac.html'},
{
@ -1841,7 +1842,7 @@ export class RdDActor extends Actor {
if (rollData.rolled.isSuccess) {
await this.chanceActuelleIncDec(-1)
}
RdDResolutionTable.displayRollData(rollData, this.name, 'chat-resultat-appelchance.html')
RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-appelchance.html')
}
/* -------------------------------------------- */
@ -1940,15 +1941,13 @@ export class RdDActor extends Actor {
return {
label: 'Rêve actuel',
value: this.getReveActuel(),
type: "number",
ignoreEtatGeneral: true
type: "number"
};
case 'chance-actuelle': case 'Chance actuelle':
return {
label: 'Chance actuelle',
value: this.getChanceActuel(),
type: "number",
ignoreEtatGeneral: true
type: "number"
};
}
return RdDActor._findCaracByName(this.data.data.carac, caracName);
@ -2210,7 +2209,7 @@ export class RdDActor extends Actor {
await entite.setEntiteReveAccordee(this);
}
await RdDResolutionTable.displayRollData(rollData, this.name, 'chat-resultat-accorder-cauchemar.html');
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-accorder-cauchemar.html');
if (rolled.isPart) {
await this._appliquerAjoutExperience(rollData, true);
}

View File

@ -1,6 +1,6 @@
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"
const nomCcategorieParade = {
const nomCategorieParade = {
"sans-armes": "Sans arme / armes naturelles",
"hast": "Armes d'hast",
"batons": "Bâtons",
@ -31,9 +31,21 @@ export class RdDItemArme extends Item {
}
/* -------------------------------------------- */
static getNomCategorieParade(it) {
const categorie = it.data ? RdDItemArme.getCategorieParade(it) : it;
return nomCcategorieParade[categorie];
static getNomCategorieParade(arme) {
const categorie = arme?.data ? RdDItemArme.getCategorieParade(arme) : arme;
return nomCategorieParade[categorie];
}
/* -------------------------------------------- */
static needArmeResist(armeAttaque, armeParade) {
if (!armeAttaque || !armeParade){
return false;
}
// Epées parant une arme de bois (cf. page 115 ), une résistance est nécessaire
let attCategory = RdDItemArme.getCategorieParade(armeAttaque);
let defCategory = RdDItemArme.getCategorieParade(armeParade);
return attCategory.match(/epees-/) && defCategory.match(/(haches|lances)/);
}
/* -------------------------------------------- */
@ -74,6 +86,9 @@ export class RdDItemArme extends Item {
/* -------------------------------------------- */
static needParadeSignificative(armeAttaque, armeParade) {
if (!armeAttaque || !armeParade){
return false;
}
// categories d'armes à la parade (cf. page 115 )
let attCategory = RdDItemArme.getCategorieParade(armeAttaque);
let defCategory = RdDItemArme.getCategorieParade(armeParade);

15
module/item-meditation.js Normal file
View File

@ -0,0 +1,15 @@
export class RdDItemMeditation {
static calculDifficulte(rollData) {
if (rollData.meditation) {
// Malus permanent éventuel
let diff = -rollData.meditation.data.malus ?? 0;
if (!rollData.conditionMeditation.isHeure) diff -= 2;
if (!rollData.conditionMeditation.isVeture) diff -= 2;
if (!rollData.conditionMeditation.isComportement) diff -= 2;
if (!rollData.conditionMeditation.isPurification) diff -= 2;
return diff;
}
return 0;
}
}

View File

@ -5,14 +5,20 @@
* to actual classes of the game system or of FoundryVTT
*/
export class Misc {
static isFunction(v) {
return v && {}.toString.call(v) === '[object Function]';
}
static upperFirst(text) {
return text.charAt(0).toUpperCase() + text.slice(1);
}
static toSignedString(number){
const value = parseInt(number)
const isPositiveNumber = value != NaN && value > 0;
return isPositiveNumber ? "+"+number : number
}
/**
* Converts the value to an integer, or to 0 if undefined/null/not representing integer
* @param {*} value value to convert to an integer using parseInt
@ -26,4 +32,13 @@ export class Misc {
const parsed = parseInt(value);
return isNaN(parsed) ? 0 : parsed;
}
static getFractionHtml(diviseur) {
if (!diviseur || diviseur <= 1) return undefined;
switch (diviseur || 1) {
case 2: return '&frac12;';
case 4: return '&frac14;';
default: return '1/' + diviseur;
}
}
}

View File

@ -13,7 +13,7 @@ export class RdDAstrologieJoueur extends Dialog {
let data = { nombres: this.organizeNombres( actor),
dates: game.system.rdd.calendrier.getJoursSuivants( 10 ),
etat: actor.data.data.compteurs.etat.value,
etat: actor.getEtatGeneral(),
ajustementsConditions: CONFIG.RDD.ajustementsConditions,
astrologie: RdDUtility.findCompetence( actor.data.items, 'Astrologie')
}

View File

@ -1,3 +1,4 @@
import { RdDCarac } from "./rdd-carac.js";
import { RdDUtility } from "./rdd-utility.js";
const conditionsTactiques = [
@ -17,6 +18,16 @@ export class RdDBonus {
return conditionsTactiques.find(e => e.type == condition) || conditionsTactiques.find(e => e.type == 'pret');
}
static isAjustementAstrologique(rollData) {
return RdDCarac.isChance(rollData.selectedCarac) ||
rollData.selectedSort?.data.isrituel;
}
/* -------------------------------------------- */
static isDefenseAttaqueFinesse(rollData) {
return rollData.attackerRoll?.particuliere == 'finesse';
}
/* -------------------------------------------- */
static dmg(rollData, dmgActor, isCauchemar = false) {
let dmg = { total: 0, loc: RdDUtility.getLocalisation() };
@ -66,11 +77,11 @@ export class RdDBonus {
/* -------------------------------------------- */
static _dmgArme(rollData) {
return rollData.arme ? parseInt(rollData.arme.data.dommages) : 0;
return parseInt(rollData.arme?.data.dommages ?? 0);
}
static _peneration(rollData) {
return rollData.arme ? parseInt(rollData.arme.data.penetration) : 0;
return parseInt(rollData.arme?.data.penetration ?? 0);
}
/* -------------------------------------------- */

30
module/rdd-carac.js Normal file
View File

@ -0,0 +1,30 @@
export class RdDCarac {
static isAgiliteOuDerivee(selectedCarac) {
return selectedCarac?.label.match(/(Agilité|Dérobée)/);
}
static isVolonte(selectedCarac) {
return selectedCarac?.label == 'Volonté';
}
static isChance(selectedCarac) {
return selectedCarac?.label?.toLowerCase()?.match(/chance( actuelle)?/);
}
static isReve(selectedCarac) {
return selectedCarac?.label?.toLowerCase()?.match(/r(e|ê)ve(( |-)actuel)?/);
}
static isIgnoreEtatGeneral(selectedCarac) {
return !selectedCarac ||
RdDCarac.isChance(selectedCarac) ||
RdDCarac.isReve(selectedCarac);
}
/**
* Lappel à la chance nest possible que pour recommencer les jets dactions physiques :
* tous les jets de combat, de FORCE, dAGILITÉ, de DEXTÉRITÉ, de Dérobée, dAPPARENCE,
* ainsi que de Perception active et volontaire.
*/
static isActionPhysique(selectedCarac) {
return selectedCarac?.label.match(/(Apparence|Force|Agilité|Dextérité|Vue|Ouïe|Odorat-Goût|Empathie|Mêlée|Tir|Lancer|Dérobée)/);
}
}

View File

@ -18,12 +18,12 @@ export class RdDCombat {
static createUsingTarget(attacker) {
const target = RdDCombat.getTarget();
if (target == undefined) {
ui.notifications.warn((game.user.targets && game.user.targets.size > 1)
ui.notifications.warn((game.user.targets?.size ?? 0) > 1
? "Vous devez choisir <strong>une seule</strong> cible à attaquer!"
: "Vous devez choisir une cible à attaquer!");
}
const defender = target ? target.actor : undefined;
const defenderTokenId = target ? target.data._id : undefined;
const defender = target?.actor;
const defenderTokenId = target?.data._id;
return this.create(attacker, defender, defenderTokenId, target)
}
@ -68,8 +68,8 @@ export class RdDCombat {
// envoyer le message au destinataire
if (!game.user.isGM || recipient.hasPlayerOwner) {
let data = {
attackerId: sender ? sender.data._id : undefined,
defenderId: recipient ? recipient.data._id : undefined,
attackerId: sender?.data._id,
defenderId: recipient?.data._id,
defenderTokenId: defenderTokenId,
rollData: duplicate(rollData),
rollMode: true
@ -86,7 +86,7 @@ export class RdDCombat {
}
/* -------------------------------------------- */
static _callJetDeVie( event ) {
static _callJetDeVie(event) {
let actorId = event.currentTarget.attributes['data-actorId'].value;
let actor = game.actors.get(actorId);
actor.jetVie();
@ -103,7 +103,7 @@ export class RdDCombat {
html.on("click", '#chat-jet-vie', event => {
event.preventDefault();
RdDCombat._callJetDeVie(event);
} );
});
}
@ -128,7 +128,7 @@ export class RdDCombat {
case '#particuliere-attaque': return await this.choixParticuliere(rollData, event.currentTarget.attributes['data-mode'].value);
case '#parer-button': {
const armeId = event.currentTarget.attributes['data-armeid'];
return this.parade(rollData, armeId ? armeId.value : undefined);
return this.parade(rollData, armeId?.value);
}
case '#esquiver-button': return this.esquive(rollData);
case '#encaisser-button': return this.encaisser(rollData, event.currentTarget.attributes['data-defenderTokenId'].value);
@ -182,7 +182,7 @@ export class RdDCombat {
options: { height: 540 }
}, {
name: 'jet-attaque',
label: 'Attaque: ' + (arme ? arme.name : competence.name),
label: 'Attaque: ' + (arme?.name ?? competence.name),
callbacks: [
this.attacker.createCallbackExperience(),
{ condition: r => (RdDCombat.isReussite(r) && !RdDCombat.isParticuliere(r)), action: r => this._onAttaqueNormale(r) },
@ -212,7 +212,7 @@ export class RdDCombat {
}
else {
// sans armes: à mains nues
rollData.arme = RdDItemArme.mainsNues({niveau: competence.data.niveau});
rollData.arme = RdDItemArme.mainsNues({ niveau: competence.data.niveau });
}
return rollData;
}
@ -247,7 +247,7 @@ export class RdDCombat {
cible: this.target ? this.defender.data.name : 'la cible',
isRecul: (rollData.particuliere == 'force' || rollData.tactique == 'charge')
}
await RdDResolutionTable.displayRollData(rollData, this.attacker.name, 'chat-resultat-attaque.html');
await RdDResolutionTable.displayRollData(rollData, this.attacker, 'chat-resultat-attaque.html');
if (!await this.accorderEntite('avant-defense')) {
return;
@ -304,7 +304,7 @@ export class RdDCombat {
return items.filter(item => RdDItemArme.getCategorieParade(item) == 'boucliers')
default:
// Le fléau ne peut être paré quau bouclier p115
if (competence.name == "Fléau"){
if (competence.name == "Fléau") {
return items.filter(item => RdDItemArme.getCategorieParade(item) == 'boucliers')
}
return items.filter(item => RdDItemArme.getCategorieParade(item));
@ -327,7 +327,7 @@ export class RdDCombat {
/* -------------------------------------------- */
async _onAttaqueEchec(rollData) {
console.log("RdDCombat.onAttaqueEchec >>>", rollData);
await RdDResolutionTable.displayRollData(rollData, this.attacker.name, 'chat-resultat-attaque.html');
await RdDResolutionTable.displayRollData(rollData, this.attacker, 'chat-resultat-attaque.html');
}
@ -376,12 +376,12 @@ export class RdDCombat {
competence: this.defender.getCompetence(compName),
arme: armeParade,
surprise: this.defender.getSurprise(),
needParadeSignificative: this.needParadeSignificative(attackerRoll, armeParade),
diviseur: this._getDiviseurSignificative(attackerRoll, armeParade),
needResist: this._needArmeResist(armeAttaque, armeParade),
needParadeSignificative: RdDItemArme.needParadeSignificative(armeAttaque, armeParade),
needResist: RdDItemArme.needArmeResist(armeAttaque, armeParade),
carac: this.defender.data.data.carac,
show: {}
};
rollData.diviseur = this._getDiviseurSignificative(rollData);
if (isCreature) {
RdDItemCompetence.setRollDataCreature(rollData);
}
@ -389,34 +389,12 @@ export class RdDCombat {
}
/* -------------------------------------------- */
_getDiviseurSignificative(attackerRoll, armeParade = undefined) {
let facteurSign = this.defender.getDiviseurSignificative();
if (RdDCombat.isAttaqueFinesse(attackerRoll)) {
_getDiviseurSignificative(rollData) {
let facteurSign = (this.defender.isDemiSurprise() || rollData.needParadeSignificative) ? 2 : 1;
if (RdDBonus.isDefenseAttaqueFinesse(rollData)) {
facteurSign *= 2;
}
if (this.needParadeSignificative(attackerRoll, armeParade)) {
facteurSign *= 2;
}
return Math.min(4, facteurSign);
}
static isAttaqueFinesse(attackerRoll) {
return attackerRoll && attackerRoll.particuliere == 'finesse';
}
needParadeSignificative(attackerRoll, armeParade) {
return attackerRoll.arme && armeParade &&
RdDItemArme.needParadeSignificative(attackerRoll.arme, armeParade);
}
/* -------------------------------------------- */
_needArmeResist(armeAttaque, armeParade) {
// Epées parant une arme de bois (cf. page 115 ), une résistance est nécessaire
let attCategory = RdDItemArme.getCategorieParade(armeAttaque);
let defCategory = RdDItemArme.getCategorieParade(armeParade);
return attCategory.match(/epees-/) && defCategory.match(/(haches|lances)/);
return facteurSign;
}
/* -------------------------------------------- */
@ -437,7 +415,7 @@ export class RdDCombat {
await this.computeRecul(rollData);
await this.computeDeteriorationArme(rollData);
await RdDResolutionTable.displayRollData(rollData, this.defender.name, 'chat-resultat-parade.html');
await RdDResolutionTable.displayRollData(rollData, this.defender, 'chat-resultat-parade.html');
}
@ -459,7 +437,7 @@ export class RdDCombat {
await this.computeRecul(rollData);
await RdDResolutionTable.displayRollData(rollData, this.defender.name, 'chat-resultat-parade.html');
await RdDResolutionTable.displayRollData(rollData, this.defender, 'chat-resultat-parade.html');
this._sendMessageEncaisser(rollData.attackerRoll);
}
@ -498,10 +476,10 @@ export class RdDCombat {
competence: competence,
surprise: this.defender.getSurprise(),
surpriseDefenseur: this.defender.getSurprise(),
diviseur: this._getDiviseurSignificative(attackerRoll),
carac: this.defender.data.data.carac,
show: {}
};
rollData.diviseur = this._getDiviseurSignificative(rollData);
if (this.defender.isCreature()) {
RdDItemCompetence.setRollDataCreature(rollData);
@ -522,7 +500,7 @@ export class RdDCombat {
async _onEsquiveNormale(rollData) {
console.log("RdDCombat._onEsquiveNormal >>>", rollData);
await RdDResolutionTable.displayRollData(rollData, this.defender.name, 'chat-resultat-esquive.html');
await RdDResolutionTable.displayRollData(rollData, this.defender, 'chat-resultat-esquive.html');
}
/* -------------------------------------------- */
@ -542,7 +520,7 @@ export class RdDCombat {
await this.computeRecul(rollData);
await RdDResolutionTable.displayRollData(rollData, this.defender.name, 'chat-resultat-esquive.html');
await RdDResolutionTable.displayRollData(rollData, this.defender, 'chat-resultat-esquive.html');
this._sendMessageEncaisser(rollData.attackerRoll);
}
@ -600,7 +578,9 @@ export class RdDCombat {
if (this._isAttaqueCauseRecul(attaque)) {
let impactRecul = this._computeImpactRecul(attaque);
const agilite = this.defender.data.data.carac.agilite.value;
const agilite = this.defender.isEntiteCauchemar()
? this.defender.data.data.carac.reve.value
: this.defender.data.data.carac.agilite.value;
let rollRecul = await RdDResolutionTable.rollData({ caracValue: 10, finalLevel: impactRecul, showDice: false });
@ -679,7 +659,7 @@ export class RdDCombat {
}
/* -------------------------------------------- */
static async displayActorCombatStatus( actor ) {
static async displayActorCombatStatus(actor) {
let rollMode = game.settings.get("core", "rollMode");
let rollData = {
alias: actor.name,
@ -691,20 +671,20 @@ export class RdDCombat {
isGrave: false,
isCritique: false
}
if ( actor.countBlessuresByName("critiques") > 0 ) { // Pour éviter le cumul grave + critique
if (actor.countBlessuresByName("critiques") > 0) { // Pour éviter le cumul grave + critique
rollData.isCritique = true;
} else if ( actor.countBlessuresByName("graves") > 0) {
} else if (actor.countBlessuresByName("graves") > 0) {
rollData.isGrave = true;
}
let content = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-summary.html`, rollData);
ChatUtility.createChatMessage({ content: content }, rollMode, actor.name);
ChatUtility.createChatMessage({ content: content }, rollMode, actor.name);
}
/* -------------------------------------------- */
static updateCombatRound( combat, data) {
static updateCombatRound(combat, data) {
if (combat.data.round != 0 && combat.turns && combat.data.active) {
let turn = combat.turns.find(t => t.tokenId == combat.current.tokenId);
this.displayActorCombatStatus( turn.actor );
this.displayActorCombatStatus(turn.actor);
// TODO Playaudio ??
}
}

View File

@ -1,8 +1,6 @@
import { ChatUtility } from "./chat-utility.js";
import { RdDItemArme } from "./item-arme.js";
import { RollDataAjustements as RollDataAjustements } from "./rolldata-ajustements.js";
import { Misc } from "./misc.js";
import { RdDBonus } from "./rdd-bonus.js";
import { RdDCombat } from "./rdd-combat.js";
import { RdDDice } from "./rdd-dice.js";
/**
@ -93,76 +91,16 @@ export class RdDResolutionTable {
}
/* -------------------------------------------- */
static async buildRollDataHtml(rollData, template = 'chat-resultat-general.html') {
rollData.ajustements = RdDResolutionTable._buildAjustements(rollData);
rollData.show = rollData.show || {};
return await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/${template}`, rollData);
static async displayRollData(rollData, actor = undefined, template = 'chat-resultat-general.html') {
ChatUtility.chatWithRollMode(
{ content: await RdDResolutionTable.buildRollDataHtml(rollData, actor, template) },
actor?.userName ?? game.user.name)
}
/* -------------------------------------------- */
static async displayRollData(rollData, userName, template = 'chat-resultat-general.html') {
ChatUtility.chatWithRollMode(
{ content: await RdDResolutionTable.buildRollDataHtml(rollData, template) },
userName)
}
static _buildAjustements(rollData) {
let list = [];
if (rollData.competence) {
list.push({ label: rollData.competence.name, value: rollData.competence.data.niveau });
}
if (rollData.tactique) {
const surprise = RdDBonus.find(rollData.tactique);
list.push({ label: surprise.descr, value: surprise.attaque });
}
if (rollData.surpriseDefenseur) {
const surprise = RdDBonus.find(rollData.surpriseDefenseur);
list.push({ label: surprise.descr, value: surprise.attaque });
}
if (rollData.diffLibre != undefined) {
const label = rollData.selectedSort ? rollData.selectedSort.name : 'Libre';
list.push({ label: label, value: rollData.diffLibre });
}
if (rollData.diffConditions != undefined) {
list.push({ label: 'Conditions', value: rollData.diffConditions });
}
if (rollData.etat != undefined) {
list.push({ label: 'Etat', value: rollData.etat });
}
if (rollData.selectedCarac != undefined && rollData.moral != undefined && rollData.selectedCarac.label == 'Volonté') {
list.push({ label: 'Moral', value: rollData.selectedCarac != undefined && rollData.moral != undefined && rollData.selectedCarac.label == 'Volonté' ? rollData.moral : undefined });
}
if (RdDResolutionTable.isAjustementAstrologique(rollData)) {
list.push({ label: 'Astrologique', value: rollData.ajustementAstrologique || 0 });
}
if (rollData.rolled.bonus && rollData.selectedSort) {
list.push({ descr: `Bonus de case: ${rollData.rolled.bonus}%` });
}
if (rollData.diviseur > 1) {
list.push({ descr: `Facteur significative &times;${RdDResolutionTable._getFractionHtml(rollData.diviseur)}` });
}
if (RdDCombat.isAttaqueFinesse(rollData.attackerRoll)) {
list.push({ descr: 'Attaque particulière en finesse' });
}
if (rollData.needParadeSignificative) {
const catAttaque = RdDItemArme.getNomCategorieParade(rollData.attackerRoll.arme);
const catParade = RdDItemArme.getNomCategorieParade(rollData.arme);
list.push({ descr: `${catAttaque} vs ${catParade}` });
}
if (rollData.surprise) {
list.push({ descr: RdDBonus.find(rollData.surprise).descr });
}
return list;
}
static _getFractionHtml(diviseur) {
if (!diviseur || diviseur <= 1) return undefined;
switch (diviseur || 1) {
case 2: return '&frac12;';
case 4: return '&frac14;';
default: return '1/' + diviseur;
}
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);
}
/* -------------------------------------------- */
@ -182,7 +120,7 @@ export class RdDResolutionTable {
rolled.caracValue = caracValue;
rolled.finalLevel = finalLevel;
rolled.bonus = bonus;
rolled.factorHtml = RdDResolutionTable._getFractionHtml(diviseur);
rolled.factorHtml = Misc.getFractionHtml(diviseur);
return rolled;
}
@ -225,10 +163,10 @@ export class RdDResolutionTable {
/* -------------------------------------------- */
static isAjustementAstrologique(rollData) {
if (rollData.selectedCarac && rollData.selectedCarac.label.toLowerCase().includes('chance')) {
if (rollData.selectedCarac?.label.toLowerCase().includes('chance')) {
return true;
}
if (rollData.selectedSort && rollData.selectedSort.data.isrituel) {
if (rollData.selectedSort?.data.isrituel) {
return true;
}
return false;
@ -323,12 +261,12 @@ export class RdDResolutionTable {
/* -------------------------------------------- */
static buildHTMLResults(caracValue, levelValue) {
let cell = this.computeChances(caracValue, levelValue);
cell.epart = cell.epart>99? 'N/A' : cell.epart;
cell.etotal = cell.etotal>100? 'N/A' : cell.etotal;
cell.epart = cell.epart > 99 ? 'N/A' : cell.epart;
cell.etotal = cell.etotal > 100 ? 'N/A' : cell.etotal;
cell.score = Math.min(cell.score, 99);
return `
<span class="span-valeur competence-label">
<span class="table-proba-reussite competence-label">
Particulière: <span class="rdd-roll-part">${cell.part}</span>
- Significative: <span class="rdd-roll-sign">${cell.sign}</span>
- Réussite: <span class="rdd-roll-norm">${cell.score}</span>

View File

@ -61,7 +61,7 @@ export class RdDRollResolutionTable extends Dialog {
async onAction(html) {
await RdDResolutionTable.rollData(this.rollData);
console.log("RdDRollResolutionTable -=>", this.rollData, this.rollData.rolled);
await RdDResolutionTable.displayRollData(this.rollData, game.user.name);
await RdDResolutionTable.displayRollData(this.rollData);
}
/* -------------------------------------------- */
@ -82,8 +82,8 @@ export class RdDRollResolutionTable extends Dialog {
$("#roll-param").text(rollData.selectedCarac.value + " / " + Misc.toSignedString(rollData.finalLevel));
$(".table-resolution").remove();
$("#resolutionTable").append(RdDResolutionTable.buildHTMLTable(rollData.caracValue, rollData.finalLevel, 1, 20, -10, 10));
$(".span-valeur").remove();
$("#resolutionValeurs").append(RdDResolutionTable.buildHTMLResults(rollData.caracValue, rollData.finalLevel));
$(".table-proba-reussite").remove();
$("#tableProbaReussite").append(RdDResolutionTable.buildHTMLResults(rollData.caracValue, rollData.finalLevel));
}
// Setup everything onload

View File

@ -1,8 +1,11 @@
import { referenceAjustements, RollDataAjustements } from "./rolldata-ajustements.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemMeditation } from "./item-meditation.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";
/**
@ -24,36 +27,40 @@ export class RdDRoll extends Dialog {
if (dialogConfig.options) {
mergeObject(options, dialogConfig.options, { overwrite: true })
}
return new RdDRoll(actor, rollData, html, options, actions, dialogConfig.close );
return new RdDRoll(actor, rollData, html, options, actions, dialogConfig.close);
}
/* -------------------------------------------- */
static _setDefaultOptions(actor, rollData) {
let defaultRollData = {
alias: actor.name,
ajustementsConditions: CONFIG.RDD.ajustementsConditions,
difficultesLibres: CONFIG.RDD.difficultesLibres,
etat: actor.data.data.compteurs.etat.value,
moral: actor.isPersonnage() ? actor.data.data.compteurs.moral.value : 0,
etat: actor.getEtatGeneral(),
moral: actor.getMoralTotal(),
carac: actor.data.data.carac,
finalLevel: 0,
diffConditions: rollData.arme ? RdDBonus.bonusAttaque(rollData.surpriseDefenseur) :0,
diffConditions: rollData.arme ? RdDBonus.bonusAttaque(rollData.surpriseDefenseur) : 0,
diffLibre: rollData.competence?.data.default_diffLibre ?? 0,
editLibre: true,
editConditions: true,
forceValue: actor.getForceValue(),
malusArmureValue: (actor.isPersonnage() && actor.data.data.attributs && actor.data.data.attributs.malusarmure) ? actor.data.data.attributs.malusarmure.value : 0,
malusArmureValue: actor.getMalusArmure(),
surencMalusFlag: actor.isPersonnage() ? (actor.data.data.compteurs.surenc.value < 0) : false,
surencMalusValue: actor.isPersonnage() ? actor.data.data.compteurs.surenc.value : 0,
surencMalusApply: false,
surencMalusValue: actor.getSurenc(),
useMalusSurenc: false,
use: {
surenc: false,
encTotal: false,
},
isMalusEncombrementTotal: RdDItemCompetence.isMalusEncombrementTotal(rollData.competence),
useMalusEncTotal: false,
encTotal: actor.getEncombrementTotal(),
encTotal: actor.getEncTotal(),
ajustementAstrologique: actor.ajustementAstrologique(),
surprise: actor.getSurprise()
surprise: actor.getSurprise(),
}
mergeObject(rollData, defaultRollData, { overwrite: false });
mergeObject(rollData, defaultRollData, { recursive: true, overwrite: false });
RollDataAjustements.calcul(rollData, actor);
}
/* -------------------------------------------- */
@ -106,47 +113,10 @@ export class RdDRoll extends Dialog {
this.bringToTop();
var rollData = this.rollData;
var actor = this.actor;
var dialog = this;
function updateRollResult(rollData) {
rollData.dmg = rollData.attackerRoll ? rollData.attackerRoll.dmg : RdDBonus.dmg(rollData, actor.getBonusDegat());
rollData.finalLevel = dialog._computeFinalLevel(rollData);
rollData.caracValue = parseInt(rollData.selectedCarac.value);
rollData.coupsNonMortels = (rollData.attackerRoll ? rollData.attackerRoll.dmg.mortalite : rollData.dmg.mortalite) == 'non-mortel';
let dmgText = Misc.toSignedString(rollData.dmg.total);
if (rollData.coupsNonMortels) {
dmgText = '(' + dmgText + ')';
}
HtmlUtility._showControlWhen($(".diffMoral"), rollData.selectedCarac == actor.data.data.carac.volonte);
HtmlUtility._showControlWhen($("#etat-general"), !dialog._isIgnoreEtatGeneral(rollData));
HtmlUtility._showControlWhen($("#ajust-astrologique"), RdDResolutionTable.isAjustementAstrologique(rollData));
// Sort management
if (rollData.selectedSort) {
rollData.bonus = RdDItemSort.getCaseBonus(rollData.selectedSort, rollData.coord),
//console.log("Toggle show/hide", rollData.selectedSort);
HtmlUtility._showControlWhen($("#div-sort-difficulte"), RdDItemSort.isDifficulteVariable(rollData.selectedSort))
HtmlUtility._showControlWhen($("#div-sort-ptreve"), RdDItemSort.isCoutVariable(rollData.selectedSort))
}
// Mise à jour valeurs
$("#roll-param").text(rollData.selectedCarac.value + " / " + Misc.toSignedString(rollData.finalLevel));
$("#compdialogTitle").text(dialog._getTitle(rollData));
$('#coupsNonMortels').prop('checked', rollData.coupsNonMortels);
$("#dmg-arme-actor").text(dmgText);
$("#defenseur-surprise").text(RdDBonus.description(rollData.surpriseDefenseur));
$(".table-resolution").remove();
$("#resolutionTable").append(RdDResolutionTable.buildHTMLTableExtract(rollData.caracValue, rollData.finalLevel));
$(".span-valeur").remove();
$("#resolutionValeurs").append(RdDResolutionTable.buildHTMLResults(rollData.caracValue, rollData.finalLevel));
}
// Setup everything onload
$(function () {
function onLoad() {
let rollData = dialog.rollData;
// Update html, according to data
if (rollData.competence) {
// Set the default carac from the competence item
@ -156,123 +126,142 @@ export class RdDRoll extends Dialog {
RdDItemSort.setCoutReveReel(rollData.selectedSort);
$("#diffLibre").val(Misc.toInt(rollData.diffLibre));
$("#diffConditions").val(Misc.toInt(rollData.diffConditions));
updateRollResult(rollData);
});
dialog.updateRollResult();
}
// Setup everything onload
$(function () { onLoad(); });
// Update !
html.find('#diffLibre').change((event) => {
rollData.diffLibre = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus
//console.log("RdDRollSelectDialog","BM CLICKED !!!", rollData);
updateRollResult(rollData);
this.rollData.diffLibre = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus
this.updateRollResult();
});
html.find('#diffConditions').change((event) => {
rollData.diffConditions = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus
//console.log("RdDRollSelectDialog","BM CLICKED !!!", rollData);
updateRollResult(rollData);
this.rollData.diffConditions = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus
this.updateRollResult();
});
html.find('#carac').change((event) => {
let caracKey = event.currentTarget.value;
this.rollData.selectedCarac = rollData.carac[caracKey]; // Update the selectedCarac
//console.log("RdDRollSelectDialog","CARAC CLICKED !!!", rollData);
updateRollResult(rollData);
this.rollData.selectedCarac = this.rollData.carac[caracKey]; // Update the selectedCarac
this.updateRollResult();
});
html.find('#draconic').change((event) => {
let draconicKey = Misc.toInt(event.currentTarget.value);
this.rollData.competence = rollData.draconicList[draconicKey]; // Update the selectedCarac
//console.log("RdDRollSelectDialog","CARAC CLICKED !!!", rollData);
updateRollResult(rollData);
this.rollData.competence = this.rollData.draconicList[draconicKey]; // Update the selectedCarac
this.updateRollResult();
});
html.find('#sort').change((event) => {
let sortKey = Misc.toInt(event.currentTarget.value);
this.rollData.selectedSort = rollData.sortList[sortKey]; // Update the selectedCarac
this.rollData.bonus = RdDItemSort.getCaseBonus(rollData.selectedSort, rollData.coord);
RdDItemSort.setCoutReveReel(rollData.selectedSort);
//console.log("RdDRollSelectDialog - Sort selection", rollData.selectedSort);
updateRollResult(rollData);
this.rollData.selectedSort = this.rollData.sortList[sortKey]; // Update the selectedCarac
this.rollData.bonus = RdDItemSort.getCaseBonus(this.rollData.selectedSort, this.rollData.coord);
RdDItemSort.setCoutReveReel(this.rollData.selectedSort);
this.updateRollResult();
});
html.find('#ptreve-variable').change((event) => {
let ptreve = Misc.toInt(event.currentTarget.value);
this.rollData.selectedSort.data.ptreve_reel = ptreve;
console.log("RdDRollSelectDialog - Cout reve", ptreve);
updateRollResult(rollData);
this.updateRollResult();
});
html.find('#ptreve-variable').change((event) => {
let ptreve = Misc.toInt(event.currentTarget.value);
this.rollData.selectedSort.data.ptreve_reel = ptreve; // Update the selectedCarac
console.log("RdDRollSelectDialog - Cout reve", ptreve);
updateRollResult(rollData);
this.updateRollResult();
});
html.find('#coupsNonMortels').change((event) => {
this.rollData.dmg.mortalite = event.currentTarget.checked ? "non-mortel" : "mortel";
updateRollResult(rollData);
this.updateRollResult();
});
html.find('#tactique-combat').change((event) => {
this.rollData.tactique = event.currentTarget.value;
updateRollResult(rollData);
this.updateRollResult();
});
html.find('#surencMalusApply').change((event) => {
this.rollData.surencMalusApply = event.currentTarget.checked;
updateRollResult(rollData);
html.find('#useMalusSurenc').change((event) => {
this.rollData.useMalusSurenc = event.currentTarget.checked;
this.updateRollResult();
});
html.find('#useMalusEncTotal').change((event) => {
this.rollData.useMalusEncTotal = event.currentTarget.checked;
updateRollResult(rollData);
this.updateRollResult();
});
// Section Méditation
html.find('#isHeure').change((event) => {
this.rollData.isHeure = event.currentTarget.checked;
updateRollResult(rollData);
html.find('.conditionMeditation').change((event) => {
let condition = event.currentTarget.attributes['id'].value;
this.rollData.conditionMeditation[condition] = event.currentTarget.checked;
this.updateRollResult();
});
html.find('#isPurification').change((event) => {
this.rollData.isPurification = event.currentTarget.checked;
updateRollResult(rollData);
});
html.find('#isVeture').change((event) => {
this.rollData.isVeture = event.currentTarget.checked;
updateRollResult(rollData);
});
html.find('#isComportement').change((event) => {
this.rollData.isComportement = event.currentTarget.checked;
updateRollResult(rollData);
});
}
/* -------------------------------------------- */
_isIgnoreEtatGeneral(rollData) {
return rollData.selectedCarac.ignoreEtatGeneral;
}
async updateRollResult() {
let rollData = this.rollData;
/* -------------------------------------------- */
_computeDiffMeditation( rollData ) {
let diff = 0;
if ( rollData.meditation ) {
diff = (!rollData.isHeure) ? diff - 2 : diff;
diff = (!rollData.isVeture) ? diff - 2 : diff;
diff = (!rollData.isComportement) ? diff - 2 : diff;
diff = (!rollData.isisPuritication) ? diff - 2 : diff;
diff = diff - rollData.meditation.data.malus; // Malus permanent éventuel
rollData.dmg = rollData.attackerRoll?.dmg ?? RdDBonus.dmg(rollData, this.actor.getBonusDegat());
rollData.caracValue = parseInt(rollData.selectedCarac.value);
rollData.coupsNonMortels = (rollData.attackerRoll?.dmg.mortalite ?? rollData.dmg.mortalite) == 'non-mortel';
let dmgText = Misc.toSignedString(rollData.dmg.total);
if (rollData.coupsNonMortels) {
dmgText = '(' + dmgText + ')';
}
return diff;
if (rollData.selectedSort) {
rollData.bonus = RdDItemSort.getCaseBonus(rollData.selectedSort, rollData.coord);
}
RollDataAjustements.calcul(rollData, this.actor);
rollData.finalLevel = this._computeFinalLevel(rollData);
HtmlUtility._showControlWhen($(".diffMoral"), rollData.ajustements.moralTotal.used);
HtmlUtility._showControlWhen($("#etat-general"), !RdDCarac.isIgnoreEtatGeneral(rollData.selectedCarac));
HtmlUtility._showControlWhen($("#ajust-astrologique"), RdDResolutionTable.isAjustementAstrologique(rollData));
// Sort management
if (rollData.selectedSort) {
rollData.bonus = RdDItemSort.getCaseBonus(rollData.selectedSort, rollData.coord);
//console.log("Toggle show/hide", rollData.selectedSort);
HtmlUtility._showControlWhen($("#div-sort-difficulte"), RdDItemSort.isDifficulteVariable(rollData.selectedSort))
HtmlUtility._showControlWhen($("#div-sort-ptreve"), RdDItemSort.isCoutVariable(rollData.selectedSort))
}
// Mise à jour valeurs
$("#compdialogTitle").text(this._getTitle(rollData));
$('#coupsNonMortels').prop('checked', rollData.coupsNonMortels);
$("#dmg-arme-actor").text(dmgText);
$("#defenseur-surprise").text(RdDBonus.description(rollData.surpriseDefenseur));
$('.table-ajustement').remove();
$(".table-resolution").remove();
$(".table-proba-reussite").remove();
$("#tableAjustements").append(await this.buildAjustements(rollData));
$("#tableResolution").append(RdDResolutionTable.buildHTMLTableExtract(rollData.caracValue, rollData.finalLevel));
$("#tableProbaReussite").append(RdDResolutionTable.buildHTMLResults(rollData.caracValue, rollData.finalLevel));
}
async buildAjustements(rollData){
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-roll-ajustements.html`, rollData);
return html;
}
/* -------------------------------------------- */
_computeFinalLevel(rollData) {
const etat = this._isIgnoreEtatGeneral(rollData) ? 0 : Misc.toInt(rollData.etat);
const etat = RdDCarac.isIgnoreEtatGeneral(rollData.selectedCarac) ? 0 : rollData.etat;
const diffConditions = Misc.toInt(rollData.diffConditions);
const malusEnc = (rollData.surencMalusApply) ? rollData.surencMalusValue : 0;
const malusSurenc = (rollData.useMalusSurenc) ? rollData.surencMalusValue : 0;
const bonusTactique = RdDBonus.bonusAttaque(rollData.tactique);
const malusEncTotal = (rollData.useMalusEncTotal) ? -rollData.encTotal : 0;
const ajustementChance = RdDResolutionTable.isAjustementAstrologique(rollData) ? rollData.ajustementAstrologique : 0;
// Gestion malus armure
const malusArmureValue = this._computeMalusArmure(rollData);
const diffMeditation = this._computeDiffMeditation( rollData );
const diffMeditation = RdDItemMeditation.calculDifficulte(rollData);
const diffLibre = this._computeDiffLibre(rollData);
const diffCompetence = this._computeDiffCompetence(rollData);
const diffMoral = rollData.selectedCarac == this.actor.data.data.carac.volonte ? rollData.moral : 0;
return etat + diffCompetence + diffLibre + diffMoral + diffConditions + malusEnc + malusEncTotal + malusArmureValue + diffMeditation + ajustementChance + bonusTactique;
let ajust = RollDataAjustements.sum(rollData.ajustements);
return ajust;
//return etat + diffCompetence + diffLibre + diffMoral + diffConditions + malusSurenc + malusEncTotal + malusArmureValue + diffMeditation + ajustementChance + bonusTactique;
}
/* -------------------------------------------- */
@ -297,7 +286,7 @@ export class RdDRoll extends Dialog {
_computeMalusArmure(rollData) {
let malusArmureValue = 0;
if (rollData.malusArmureValue != 0 && (rollData.selectedCarac.label == "Agilité" || rollData.selectedCarac.label == "Dérobée")) {
if (rollData.malusArmureValue && (rollData.selectedCarac.label == "Agilité" || rollData.selectedCarac.label == "Dérobée")) {
$("#addon-message").text("Malus armure appliqué : " + rollData.malusArmureValue);
malusArmureValue = rollData.malusArmureValue;
} else {

View File

@ -239,7 +239,7 @@ export class RdDTMRDialog extends Dialog {
const draconic = this.actor.getBestDraconic();
const carac = this.actor.getReveActuel();
const etatGeneral = this.actor.data.data.compteurs.etat.value;
const etatGeneral = this.actor.getEtatGeneral();
const difficulte = draconic.data.niveau - this.currentRencontre.force + etatGeneral;
console.log("Maitriser", carac, draconic.data.niveau, this.currentRencontre.force, etatGeneral);
@ -329,7 +329,7 @@ export class RdDTMRDialog extends Dialog {
tmrpos.innerHTML = this.actor.data.data.reve.tmrpos.coord + " (" + tmr.label + ")";
let etat = document.getElementById("tmr-etatgeneral-value");
etat.innerHTML = this.actor.data.data.compteurs.etat.value;
etat.innerHTML = this.actor.getEtatGeneral();
let refoulement = document.getElementById("tmr-refoulement-value");
refoulement.innerHTML = this.actor.data.data.reve.refoulement.value;
@ -389,7 +389,7 @@ export class RdDTMRDialog extends Dialog {
let draconic = this.actor.getBestDraconic();
let carac = this.actor.getReveActuel();
const etatGeneral = this.actor.data.data.compteurs.etat.value
const etatGeneral = this.actor.getEtatGeneral();
let difficulte = draconic.data.niveau - 7;
let rolled = await RdDResolutionTable.roll(carac, difficulte);

View File

@ -183,6 +183,7 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/niveau-ethylisme.html',
'systems/foundryvtt-reve-de-dragon/templates/casetmr-specific-list.html',
// Dialogs
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-ajustements.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-resolution.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-carac.html',
@ -673,10 +674,8 @@ export class RdDUtility {
/* -------------------------------------------- */
static currentFatigueMalus( value, max)
{
max = (max < 16) ? 16 : max;
max = (max > 30) ? 30 : max;
value = (value > max*2) ? max*2 : value;
value = (value < 0) ? 0 : value;
max = Math.max(1, Math.min(max, 60));
value = Math.min(max*2, Math.max(0, value));
let fatigueTab = fatigueMatrix[max];
let fatigueRem = value;

View File

@ -0,0 +1,150 @@
import { RdDItemArme } from "./item-arme.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemMeditation } from "./item-meditation.js";
import { RdDItemSort } from "./item-sort.js";
import { Misc } from "./misc.js";
import { RdDBonus } from "./rdd-bonus.js";
import { RdDCarac } from "./rdd-carac.js";
/**
* tous les ajustements pouvant s'appliquer.
* un ajustement se compose de `function(rollData, actor)` :
* - isVisible: indique si l'ajustement sera visible (pour les cas il peut être sélectionné)
* - isUsed: évalue si l'ajustement indique s'il est actif ou non
* - getLabel: un libellé texte pour l'affichage de l'ajustement
* - getValue: une valeur numérique correspondant à un modificateur entier
* - getDescr: une valeur textuelle pour les informations non numériques (demi-surprise, bonus de case, ...)
*/
export const referenceAjustements = {
competence: {
isUsed: (rollData, actor) => rollData.competence,
getLabel: (rollData, actor) => rollData.competence?.name,
getValue: (rollData, actor) => rollData.competence?.data?.niveau,
},
meditation: {
isUsed: (rollData, actor) => rollData.meditation,
getLabel: (rollData, actor) => 'Méditation',
getValue: (rollData, actor) => RdDItemMeditation.calculDifficulte(rollData)
},
diffLibre: {
isUsed: (rollData, actor) => rollData.diffLibre != undefined,
getLabel: (rollData, actor) => rollData.selectedSort?.name ?? rollData.attackerRoll ? 'Imposée' : 'Libre',
getValue: (rollData, actor) => rollData.selectedSort
? RdDItemSort.getDifficulte(rollData.selectedSort, rollData.diffLibre)
: rollData.diffLibre ?? rollData.competence?.data.default_diffLibre ?? 0
},
diffConditions: {
isUsed: (rollData, actor) => rollData.diffConditions != undefined,
getLabel: (rollData, actor) => 'Conditions',
getValue: (rollData, actor) => rollData.diffConditions
},
tactique: {
isUsed: (rollData, actor) => rollData.tactique,
getLabel: (rollData, actor) => RdDBonus.find(rollData.tactique).descr,
getValue: (rollData, actor) => RdDBonus.find(rollData.tactique).attaque,
},
attaqueDefenseurSurpris: {
isUsed: (rollData, actor) => rollData.surpriseDefenseur,
getLabel: (rollData, actor) => RdDBonus.find(rollData.surpriseDefenseur).descr,
getValue: (rollData, actor) => RdDBonus.find(rollData.surpriseDefenseur).attaque,
},
etat: {
isUsed: (rollData, actor) => !RdDCarac.isIgnoreEtatGeneral(rollData.selectedCarac),
getLabel: (rollData, actor) => 'Etat général',
getValue: (rollData, actor) => actor.getEtatGeneral()
},
malusArmure: {
isVisible: (rollData, actor) => RdDCarac.isAgiliteOuDerivee(rollData.competence),
isUsed: (rollData, actor) => RdDCarac.isAgiliteOuDerivee(rollData.selectedCarac),
getLabel: (rollData, actor) => 'Malus armure',
getValue: (rollData, actor) => actor.getMalusArmure()
},
encTotal: {
isVisible: (rollData, actor) => RdDItemCompetence.isMalusEncombrementTotal(rollData.competence),
isUsed: (rollData, actor) => rollData.useMalusEncTotal,
getLabel: (rollData, actor) => 'Encombrement total',
getValue: (rollData, actor) => -actor.getEncTotal()
},
surenc: {
isVisible: (rollData, actor) => rollData.useMalusSurenc,
isUsed: (rollData, actor) => rollData.useMalusSurenc,
getLabel: (rollData, actor) => 'Sur-encombrement',
getValue: (rollData, actor) => actor.getSurenc()
},
moral: {
isVisible: (rollData, actor) => RdDCarac.isActionPhysique(rollData.selectedCarac),
isUsed: (rollData, actor) => rollData.use?.moral,
getLabel: (rollData, actor) => 'Moral',
getValue: (rollData, actor) => 1
},
moralTotal: {
isUsed: (rollData, actor) => RdDCarac.isVolonte(rollData.selectedCarac),
getLabel: (rollData, actor) => 'Moral',
getValue: (rollData, actor) => actor.getMoralTotal()
},
astrologique: {
isUsed: (rollData, actor) => RdDBonus.isAjustementAstrologique(rollData),
getLabel: (rollData, actor) => 'Astrologique',
getValue: (rollData, actor) => actor.ajustementAstrologique()
},
facteurSign: {
isUsed: (rollData, actor) => rollData.diviseur > 1,
getDescr: (rollData, actor) => rollData.diviseur > 1 ? `Facteur significative &times;${Misc.getFractionHtml(rollData.diviseur)}` : ''
},
finesse: {
isUsed: (rollData, actor) => RdDBonus.isDefenseAttaqueFinesse(rollData),
getDescr: (rollData, actor) => 'Attaque particulière en finesse',
},
armeParade: {
isUsed: (rollData, actor) => RdDItemArme.needParadeSignificative(rollData.attackerRoll?.arme, rollData.arme),
getDescr: (rollData, actor) => rollData.attackerRoll && rollData.arme? `${RdDItemArme.getNomCategorieParade(rollData.attackerRoll?.arme)} vs ${RdDItemArme.getNomCategorieParade(rollData.arme)}`: ''
},
surprise: {
isUsed: (rollData, actor) => actor.getSurprise(),
getDescr: (rollData, actor) => RdDBonus.find(actor.getSurprise()).descr
},
bonusCase: {
isUsed: (rollData, actor) => rollData.selectedSort && rollData.coord,
getDescr: (rollData, actor) => rollData.selectedSort && rollData.coord ? `Bonus de case: ${RdDItemSort.getCaseBonus(rollData.selectedSort, rollData.coord)}%`: ''
}
}
export class RollDataAjustements {
/* -------------------------------------------- */
static calcul(rollData, actor) {
rollData.ajustements = {};
for (var key in referenceAjustements) {
const reference = referenceAjustements[key];
rollData.ajustements[key] = {
used: reference.isUsed(rollData, actor),
label: reference.getLabel && reference.getLabel(rollData, actor),
value: reference.getValue && reference.getValue(rollData, actor),
descr: reference.getDescr && reference.getDescr(rollData, actor)
}
}
}
// /* -------------------------------------------- */
// static calculListe(ajustements, rollData, actor) {
// let list = [];
// for (var key in referenceAjustements) {
// if (referenceAjustements[key].isUsed(rollData, actor)) {
// list.push(Ajustements._apply(referenceAjustements[key], rollData, actor));
// }
// }
// return list;
// }
/* -------------------------------------------- */
static sum(ajustements) {
let sum = 0;
for (var key in ajustements) {
if (ajustements[key].used && !ajustements[key].descr) {
sum += ajustements[key].value;
}
}
return sum;
}
}

View File

@ -410,7 +410,7 @@ table {border: 1px solid #7a7971;}
background-color: lightblue;
}
#resolutionValeurs{
#tableProbaReussite{
font-size: 0.8rem;
padding: 5px;
}
@ -737,6 +737,9 @@ ul, li {
.rdd-hud-menu label {
font-size: 0.75rem;
}
#token-hud .status-effects.active{
z-index: 2;
}
/* ======================================== */
.item-checkbox {
height: 25px;
@ -1253,7 +1256,7 @@ display: inline-flex;
.tooltip .ttt-ajustements {
width: 150px;
background: rgba(220,220,210,0.9);
background: rgba(220,220,210,0.95);
border-radius: 6px;
font-size: 0.9rem;
padding: 3px 0;

View File

@ -4,6 +4,7 @@
{{#if ajustements}}
<div class="tooltiptext ttt-ajustements">
{{#each ajustements as |item key|}}
{{#if item.used}}
<div class="{{#if item.strong}}strong-text{{/if}}">
{{#if item.descr}}
{{{item.descr}}}
@ -11,6 +12,7 @@
{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}
{{/if}}
</div>
{{/if}}
{{/each}}
</div>
{{/if}}

View File

@ -1,5 +1,5 @@
<h4>{{alias}} attaque: {{arme.name}}</h4>
<div>{{selectedCarac.label}} / {{competence.name}}, difficulté {{diffLibre}}</div>
<div>{{selectedCarac.label}}{{#unless (eq selectedCarac.label competence.name)}} / {{competence.name}}{{/unless}}, difficulté {{diffLibre}}</div>
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}
<hr>
{{#if tactique}}

View File

@ -1,7 +1,9 @@
<h4>
{{alias}} {{show.title}}:
{{#if selectedCarac}}{{selectedCarac.label}}
{{#if competence}} / {{competence.name}}{{/if}}
{{#if competence}}
{{#unless (eq selectedCarac.label competence.name)}} / {{competence.name}}{{/unless}} / {{competence.name}}
{{/if}}
{{/if}}
</h4>
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}

View File

@ -1,5 +1,5 @@
<h4>{{alias}} esquive</h4>
<div>{{selectedCarac.label}} / {{competence.name}} attaque à {{diffLibre}}</div>
<h4>{{alias}} esquive une attaque à {{diffLibre}}</h4>
<div>{{selectedCarac.label}}{{#unless (eq selectedCarac.label competence.name)}} / {{competence.name}}{{/unless}}</div>
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}
<hr>
<div>

View File

@ -1,7 +1,7 @@
<h4>
{{alias}} {{#if show.title}}{{show.title}}: {{/if}}
{{#if selectedCarac}}{{selectedCarac.label}}
{{#if competence}} / {{competence.name}}{{/if}}
{{#if competence}}{{#unless (eq selectedCarac.label competence.name)}} / {{competence.name}}{{/unless}}{{/if}}
à {{diffLibre}}
{{/if}}
</h4>

View File

@ -1,5 +1,5 @@
<h4>{{alias}} pare: {{arme.name}}</h4>
<div>{{selectedCarac.label}} / {{competence.name}}, attaque à {{diffLibre}}</div>
<h4>{{alias}} pare une attaque à {{diffLibre}} - {{arme.name}}</h4>
<div>{{selectedCarac.label}}{{#unless (eq selectedCarac.label competence.name)}} / {{competence.name}}{{/unless}}</div>
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}
<hr>
<div>

View File

@ -59,18 +59,15 @@
{{/if}}
</div>
{{/if}}
<div class="form-group">
<label for="categorie">Ajustements</label>
<label for="categorie">Etat général: {{numberFormat etat decimals=0 sign=true}}</label>
<label for="categorie" id="ajust-astrologique">Astrologique: {{numberFormat ajustementAstrologique decimals=0 sign=true}}</label>
<label>Final: <label id="roll-param">10 / 0</label>&nbsp;&nbsp;&nbsp;<label name="addon-message" id="addon-message"></label></label>
</div>
{{>"systems/foundryvtt-reve-de-dragon/templates/dialog-roll-surenc.html"}}
{{>"systems/foundryvtt-reve-de-dragon/templates/dialog-roll-enctotal.html"}}
<div id="resolutionTable">
<div id="tableAjustements">
</div>
<div id="resolutionValeurs">
<div id="tableResolution">
</div>
<div id="tableProbaReussite">
</div>
</form>

View File

@ -0,0 +1,19 @@
<div class="table-ajustement">
<label class="tooltip">
<span>Ajustement Final:</span>
<span id="roll-param">{{selectedCarac.value}} / {{numberFormat finalLevel decimals=0 sign=true}}</span>
<div class="tooltiptext ttt-ajustements">
{{#each ajustements as |item key|}}
{{#if item.used}}
<div class="{{#if item.strong}}strong-text{{/if}}">
{{#if item.descr}}
{{{item.descr}}}
{{else}}
{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}
{{/if}}
</div>
{{/if}}
{{/each}}
</div>
</label>
</div>

View File

@ -20,15 +20,11 @@
<label class="diffMoral" for="categorie">Moral: {{#if (gt moral 0)}}+{{/if}}{{moral}}</label>
</div>
{{>"systems/foundryvtt-reve-de-dragon/templates/dialog-roll-surenc.html"}}
<div class="form-group">
<label for="categorie">Ajustements</label>
<label for="categorie" id="etat-general">Etat général: {{numberFormat etat decimals=0 sign=true}}</label>
<label for="categorie" id="ajust-astrologique">Astrologique: {{numberFormat ajustementAstrologique decimals=0 sign=true}}</label>
<label>Final: <label id="roll-param">10 / 0</label>&nbsp;&nbsp;&nbsp;<label name="addon-message" id="addon-message"></label></label>
<div id="tableAjustements">
</div>
<div id="resolutionTable">
<div id="tableResolution">
</div>
<div id="resolutionValeurs">
<div id="tableProbaReussite">
</div>
</form>

View File

@ -1,6 +1,7 @@
{{#if isMalusEncombrementTotal}}
{{#if ajustements.encTotal.visible}}
<div class="form-group">
<label for="xp">Appliquer l'encombrement total comme malus (-{{encTotal}} ) ? </label>
<input class="attribute-value" type="checkbox" id="useMalusEncTotal" name="useMalusEncTotal" {{#if useMalusEncTotal}}checked{{/if}}/>
<label>Appliquer l'encombrement total comme malus ({{encTotal}}) ? </label>
<input class="attribute-value" type="checkbox" id="ajustements-encTotal-apply"
name="ajustements.encTotal.apply" {{#if ajustements.encTotal.apply}}checked{{/if}}/>
</div>
{{/if}}

View File

@ -21,9 +21,9 @@
<label>Ajustement final : <label id="roll-param">10 / 0</label>&nbsp;&nbsp;&nbsp;<label name="addon-message" id="addon-message"></label></label>
</div>
<div id="resolutionTable">
<div id="tableResolution">
</div>
<div id="resolutionValeurs">
<div id="tableProbaReussite">
</div>
</form>

View File

@ -24,19 +24,19 @@
<ul class="item-list">
<li class="item flexrow">
<label for="categorie">Heure : {{meditation.data.heure}}</label>
<input class="attribute-value" type="checkbox" id="isHeure" name="isHeure" {{#if isHeure}}checked{{/if}}/>
<input class="attribute-value conditionMeditation" type="checkbox" id="isHeure" {{#if conditionMeditation.isHeure}}checked{{/if}}/>
</li>
<li class="item flexrow">
<label for="categorie">Purification : {{meditation.data.purification}}</label>
<input class="attribute-value" type="checkbox" id="isPurification" name="isPurification" {{#if isPurification}}checked{{/if}}/>
<input class="attribute-value conditionMeditation" type="checkbox" id="isPurification" {{#if conditionMeditation.isPurification}}checked{{/if}}/>
</li>
<li class="item flexrow">
<label for="categorie">Vêture : {{meditation.data.veture}}</label>
<input class="attribute-value" type="checkbox" id="isVeture" name="isVeture" {{#if isVeture}}checked{{/if}}/>
<input class="attribute-value conditionMeditation" type="checkbox" id="isVeture" {{#if conditionMeditation.isVeture}}checked{{/if}}/>
</li>
<li class="item flexrow">
<label for="categorie">Comportement antérieur : {{meditation.data.comportement}})</label>
<input class="attribute-value" type="checkbox" id="isComportement" name="isComportement" {{#if isComportement}}checked{{/if}}/>
<label for="categorie">Comportement antérieur : {{meditation.data.comportement}}</label>
<input class="attribute-value conditionMeditation" type="checkbox" id="isComportement" {{#if conditionMeditation.isComportement}}checked{{/if}}/>
</li>
</ul>
@ -51,14 +51,11 @@
</select>
</div>
<div class="form-group">
<label for="categorie">Ajustements</label>
<label for="categorie" id="etat-general">Etat général: {{numberFormat etat decimals=0 sign=true}}</label>
<label>Final: <label id="roll-param">10 / 0</label>&nbsp;&nbsp;&nbsp;<label name="addon-message" id="addon-message"></label></label>
<div id="tableAjustements">
</div>
<div id="resolutionTable">
<div id="tableResolution">
</div>
<div id="resolutionValeurs">
<div id="tableProbaReussite">
</div>
</form>

View File

@ -28,9 +28,11 @@
{{/select}}
</select>
</div>
<div id="resolutionTable">
<div id="tableAjustements">
</div>
<div id="resolutionValeurs">
<div id="tableResolution">
</div>
<div id="tableProbaReussite">
</div>
</form>

View File

@ -57,15 +57,11 @@
</select>
</div>
<div class="form-group">
<label for="categorie">Ajustements</label>
<label for="categorie" id="etat-general">Etat général: {{numberFormat etat decimals=0 sign=true}}</label>
<label for="categorie" id="ajust-astrologique">Astrologique: {{numberFormat ajustementAstrologique decimals=0 sign=true}}</label>
<label>Final: <label id="roll-param">10 / 0</label>&nbsp;&nbsp;&nbsp;<label name="addon-message" id="addon-message"></label></label>
<div id="tableAjustements">
</div>
<div id="resolutionTable">
<div id="tableResolution">
</div>
<div id="resolutionValeurs">
<div id="tableProbaReussite">
</div>
</form>

View File

@ -1,6 +1,6 @@
{{#if surencMalusFlag}}
<div class="form-group">
<label for="xp">Appliquer le malus de sur-encombrement ? </label>
<input class="attribute-value" type="checkbox" id="surencMalusApply" name="surencMalusApply" {{#if surencMalusApply}}checked{{/if}}/>
<input class="attribute-value" type="checkbox" id="useMalusSurenc" name="useMalusSurenc" {{#if useMalusSurenc}}checked{{/if}}/>
</div>
{{/if}}