diff --git a/module/actor-sheet.js b/module/actor-sheet.js index f8836363..ae6a0d3b 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -459,7 +459,7 @@ export class RdDActorSheet extends ActorSheet { this.actor.setEthylisme(parseInt(event.target.value)); }); html.find('#stress-test').click((event) => { - this.actor.stressTest(); + this.actor.transformerStress(); this.render(true); }); html.find('#moral-malheureux').click((event) => { diff --git a/module/actor.js b/module/actor.js index 5ae26497..1e3aaa73 100644 --- a/module/actor.js +++ b/module/actor.js @@ -207,6 +207,10 @@ export class RdDActor extends Actor { } return 10; } + /* -------------------------------------------- */ + getChance() { + return Misc.toInt(this.data.data.carac.chance?.value ?? 10); + } getMoralTotal() { return Misc.toInt(this.data.data.compteurs.moral?.value); } @@ -315,7 +319,9 @@ export class RdDActor extends Actor { await this._recupererBlessures(message, "critique", blessures.critiques.liste.filter(b => b.active), blessures.graves.liste); await this.update({ "data.blessures": blessures }); await this._recupererVie(message); - await this.transformerStress(message); + await this.jetDeMoral('neutre'); + await this.chanceActuelleIncDec(1); + this.transformerStress(); await this.retourSeuilDeReve(message); message.content = `A la fin Chateau Dormant, ${message.content}
Un nouveau jour se lève`; ChatMessage.create(message); @@ -1411,69 +1417,72 @@ export class RdDActor extends Actor { } /* -------------------------------------------- */ - async stressTest() { - const message = { - content: "", - whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name) - }; - await this.transformerStress(message); - ChatMessage.create(message); - } - - /* -------------------------------------------- */ - async transformerStress(message) { - let compteurs = duplicate(this.data.data.compteurs); - const stress = Misc.toInt(compteurs.stress.value); - + async transformerStress() { + const stress = Misc.toInt(this.data.data.compteurs.stress.value); if (stress <= 0) { - return false; + return; } - - let stressRoll = await this._stressRoll(); - let convertis = Math.floor(stress * stressRoll.factor); - compteurs.stress.value = Math.max(stress - convertis - 1, 0); - - let dissolution = Math.max(0, Misc.toInt(compteurs.dissolution.value)); - let exaltation = Math.max(0, Misc.toInt(compteurs.exaltation.value)); + + const stressRoll = await this._stressRoll(this.getReveActuel()); + + const conversion = Math.floor(stress * stressRoll.factor / 100); + let dissolution = Math.max(0, Misc.toInt(this.data.data.compteurs.dissolution.value)); + let exaltation = Math.max(0, Misc.toInt(this.data.data.compteurs.exaltation.value)); const annule = Math.min(dissolution, exaltation); dissolution -= annule; exaltation -= annule; - if (dissolution > 0) { - const perdus = Math.min(dissolution, convertis); - convertis -= perdus; - dissolution -= perdus; - } - compteurs.experience.value += convertis + exaltation; - compteurs.dissolution.value = dissolution; + const perteDissolution = Math.max(0, Math.min(dissolution, conversion)); + + let stressRollData = { + alias: this.name, + selectedCarac: this.data.data.carac.reve, + rolled: stressRoll, + stress: stress, + perte: Math.min(conversion, stress), + convertis: conversion - perteDissolution, + xp: conversion - perteDissolution + exaltation, + dissolution: dissolution, + exaltation: exaltation + }; + + ChatMessage.create({ + whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), + content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-transformer-stress.html`, stressRollData) + }); + + let compteurs = duplicate(this.data.data.compteurs); + compteurs.stress.value = Math.max(stress - stressRollData.perte - 1, 0); + compteurs.experience.value += stressRollData.xp; + compteurs.dissolution.value = dissolution - perteDissolution; compteurs.exaltation.value = 0; - message.content += "
Vous transformez " + convertis + " points de Stress en Expérience" + stressRoll.comment; await this.update({ "data.compteurs": compteurs }); - return true; } /* -------------------------------------------- */ - async _stressRoll() { - let reveActuel = this.getReveActuel(); + async _stressRoll(reveActuel) { let result = await RdDResolutionTable.roll(reveActuel, 0); - console.log("_stressRoll", result); - switch (result.code) { - case "sign": return { factor: 0.75, comment: " (75%): " + result.quality + " - " + result.roll + " sur " + result.score + "%" } - case "norm": return { factor: 0.5, comment: " (50%): " + result.quality + " - " + result.roll + " sur " + result.score + "%" } - case "echec": return { factor: 0.2, comment: " (20%): " + result.quality + " - " + result.roll + " sur " + result.score + "%" } - case "epart": return { factor: 0.1, comment: " (10%): " + result.quality + " - " + result.roll + " sur " + result.score + "%" } - case "etotal": return { factor: 0, comment: " (0%): " + result.quality + " - " + result.roll + " sur " + result.score + "%" } - case "part": - { - let second = await RdDResolutionTable.roll(reveActuel, 0); - console.log("_stressRoll", second); - switch (second.code) { - case "part": case "sign": - return { factor: 1.5, comment: " (150%): Double Particulière - " + result.roll + " puis " + second.roll + " sur " + result.score + "%" } - default: - return { factor: 1, comment: " (100%): " + result.quality + " - " + result.roll + " puis " + second.roll + " sur " + result.score + "%" } - } - } + if (result.isPart) { + result.second = await RdDResolutionTable.roll(reveActuel, 0); } + result.factor = this._getFacteurStress(result); + return result; + } + + _getFacteurStress(stressRoll) { + switch (stressRoll.code) { + case "sign": return 75; + case "norm": return 50; + case "echec": return 20; + case "epart": return 10; + case "etotal": return 0; + case "part": + if (stressRoll.second.isSign) { + stressRoll.quality = "Double Particulière"; + return 150; + } + return 100; + } + return 0; } /* -------------------------------------------- */ @@ -2156,7 +2165,7 @@ export class RdDActor extends Actor { async _appelChanceResult(rollData, onSuccess = () => { }, onEchec = () => { }) { await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-appelchance.html') if (rollData.rolled.isSuccess) { - await this.chanceActuelleIncDec(-1) + await this.chanceActuelleIncDec(-1); onSuccess(); } else { @@ -2165,9 +2174,12 @@ export class RdDActor extends Actor { } /* -------------------------------------------- */ - async chanceActuelleIncDec(value) { + async chanceActuelleIncDec(value, limit=true) { let chance = duplicate(this.data.data.compteurs.chance); chance.value = Math.max(chance.value + value, 0); + if (limit) { + chance.value = Math.min(chance.value, this.getChance()) + } await this.update({ "data.compteurs.chance": chance }); } diff --git a/module/item-arme.js b/module/item-arme.js index 4e9fbd76..048543f0 100644 --- a/module/item-arme.js +++ b/module/item-arme.js @@ -144,6 +144,9 @@ export class RdDItemArme extends Item { return arme; } + static isArmeUtilisable(item) { + return item.type == 'arme' && item.data.resistance > 0; + } static mainsNues(actorData={}) { const mainsNues = { diff --git a/module/item-competencecreature.js b/module/item-competencecreature.js index 5d3235a4..524d5829 100644 --- a/module/item-competencecreature.js +++ b/module/item-competencecreature.js @@ -1,7 +1,6 @@ /* -------------------------------------------- */ export class RdDItemCompetenceCreature extends Item { - /* -------------------------------------------- */ static setRollDataCreature(rollData) { rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.data.carac_value } }; @@ -17,7 +16,7 @@ export class RdDItemCompetenceCreature extends Item { /* -------------------------------------------- */ static toArme(item) { - if (item.type == 'competencecreature' && item.data.iscombat) { + if (RdDItemCompetenceCreature.isCompetenceAttaque(item)) { let arme = { name: item.name, data: duplicate(item.data) }; mergeObject(arme.data, { @@ -34,4 +33,11 @@ export class RdDItemCompetenceCreature extends Item { return undefined; } + static isCompetenceAttaque(item) { + return item.type == 'competencecreature' && item.data.iscombat; + } + + static isCompetenceParade(item) { + return item.type == 'competencecreature' && item.data.isparade; + } } diff --git a/module/rdd-combat.js b/module/rdd-combat.js index 35af36ed..98556587 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -510,7 +510,7 @@ export class RdDCombat { /* -------------------------------------------- */ _filterArmesParade(items, competence) { - items = items.filter(item => (item.type == 'arme' && item.data.equipe) || (item.type == 'competencecreature' && item.data.isparade)); + items = items.filter(item => RdDItemArme.isArmeUtilisable(item) || RdDItemCompetenceCreature.isCompetenceParade(item)); switch (competence.data.categorie) { case 'tir': case 'lancer': @@ -743,20 +743,20 @@ export class RdDCombat { } /* -------------------------------------------- */ - async computeDeteriorationArme(rollData) { + async computeDeteriorationArme(defenderRoll) { if (!ReglesOptionelles.isUsing('resistanceArmeParade')) { return; } - const attackerRoll = rollData.attackerRoll; + const attackerRoll = defenderRoll.attackerRoll; // Est-ce une parade normale? - if (rollData.arme && attackerRoll && !rollData.rolled.isPart) { + if (defenderRoll.arme && attackerRoll && !defenderRoll.rolled.isPart) { // Est-ce que l'attaque est une particulière en force ou une charge - if (rollData.needResist || attackerRoll.particuliere == 'force' || attackerRoll.tactique == 'charge') { + if (defenderRoll.needResist || this._isForceOuCharge(attackerRoll)) { - rollData.show = rollData.show || {} + defenderRoll.show = defenderRoll.show || {} const dmg = attackerRoll.dmg.dmgArme + attackerRoll.dmg.dmgActor; - let resistance = Misc.toInt(rollData.arme.data.resistance); + let resistance = Misc.toInt(defenderRoll.arme.data.resistance); let msg = ""; // Jet de résistance de l'arme de parade (p.132) let resistRoll = await RdDResolutionTable.rollData({ @@ -765,26 +765,21 @@ export class RdDCombat { showDice: false }); if (resistRoll.rolled.isSuccess) { // Perte de résistance - rollData.show.deteriorationArme = 'resiste'; + defenderRoll.show.deteriorationArme = 'resiste'; } else { resistance -= dmg; - if (resistance <= 0) { - this.defender.deleteEmbeddedEntity("OwnedItem", rollData.arme._id); - rollData.show.deteriorationArme = 'brise'; - } else { - this.defender.updateEmbeddedEntity("OwnedItem", { _id: rollData.arme._id, 'data.resistance': resistance }); - rollData.show.deteriorationArme = 'perte'; - rollData.show.perteResistance = dmg; - } + defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise': 'perte'; + defenderRoll.show.perteResistance = dmg; + this.defender.updateEmbeddedEntity("OwnedItem", { _id: defenderRoll.arme._id, 'data.resistance': resistance }); } // Si l'arme de parade n'est pas un bouclier, jet de désarmement (p.132) - if (ReglesOptionelles.isUsing('defenseurDesarme') && resistance > 0 && RdDItemArme.getCategorieParade(rollData.arme) != 'boucliers') { + if (ReglesOptionelles.isUsing('defenseurDesarme') && resistance > 0 && RdDItemArme.getCategorieParade(defenderRoll.arme) != 'boucliers') { let desarme = await RdDResolutionTable.rollData({ caracValue: this.defender.getForce(), - finalLevel: Misc.toInt(rollData.competence.data.niveau) - dmg, + finalLevel: Misc.toInt(defenderRoll.competence.data.niveau) - dmg, showDice: false }); - rollData.show.desarme = desarme.rolled.isEchec; + defenderRoll.show.desarme = desarme.rolled.isEchec; } } } @@ -793,7 +788,7 @@ export class RdDCombat { /* -------------------------------------------- */ async computeRecul(defenderRoll) { // Calcul du recul (p. 132) const attackerRoll = defenderRoll.attackerRoll; - if (ReglesOptionelles.isUsing('recul') && this._isAttaqueCauseRecul(attackerRoll)) { + if (ReglesOptionelles.isUsing('recul') && this._isForceOuCharge(attackerRoll)) { const impact = this._computeImpactRecul(attackerRoll); const rollRecul = await RdDResolutionTable.rollData({ caracValue: 10, finalLevel: impact }); if (rollRecul.rolled.isSuccess) { @@ -816,7 +811,7 @@ export class RdDCombat { } /* -------------------------------------------- */ - _isAttaqueCauseRecul(attaque) { + _isForceOuCharge(attaque) { return attaque.particuliere == 'force' || attaque.tactique == 'charge'; } diff --git a/module/rdd-commands.js b/module/rdd-commands.js index 1523cb26..8190042c 100644 --- a/module/rdd-commands.js +++ b/module/rdd-commands.js @@ -249,7 +249,7 @@ export class RdDCommands { getCoutXpCarac(msg, params) { if (params && params.length == 1) { let to = Number(params[0]); - RdDCommands._chatAnswer(msg, `Coût pour passer une caractéristique de ${to - 1} à ${to}: ${RdDUtility.getCaractXp(to)}`); + RdDCommands._chatAnswer(msg, `Coût pour passer une caractéristique de ${to - 1} à ${to}: ${RdDUtility.getCaracXp(to)}`); } else { return false; diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 20c16708..98dd7db5 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -412,11 +412,11 @@ export class RdDUtility { static getCaracNextXp(value) { const nextValue = Number(value) + 1; // xp est le coût pour atteindre cette valeur, on regarde donc le coût de la valeur+1 - return RdDUtility.getCaractXp(nextValue); + return RdDUtility.getCaracXp(nextValue); } - static getCaractXp(targetValue) { - return tableCaracDerivee[targetValue].xp; + static getCaracXp(targetValue) { + return tableCaracDerivee[targetValue]?.xp ?? 200 ; } /* -------------------------------------------- */ @@ -715,11 +715,11 @@ export class RdDUtility { let items = actor.data.items; let actions = [] if (actor.isCreature()) { - actions = actions.concat(items.filter(it => it.type == 'competencecreature' && it.data.iscombat) + actions = actions.concat(items.filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it)) .map(competence => RdDItemCompetenceCreature.toArme(competence))); } else { // Recupération des items 'arme' - let armes = items.filter(it => it.type == 'arme') + let armes = items.filter(it => RdDItemArme.isArmeUtilisable(it)) .map(arme => duplicate(arme)) /* pas de changements aux armes d'origine */ .concat(RdDItemArme.mainsNues()); diff --git a/template.json b/template.json index cf971e9c..b7e9b81f 100644 --- a/template.json +++ b/template.json @@ -434,12 +434,12 @@ "reve": { "reve": { "max": 0, - "value": 0, + "value": 10, "label": "Points de Rêve actuels" }, "seuil": { "max": 0, - "value": 0, + "value": 10, "label": "Seuil de Rêve" }, "tmrpos": { diff --git a/templates/chat-resultat-transformer-stress.html b/templates/chat-resultat-transformer-stress.html new file mode 100644 index 00000000..0bef2112 --- /dev/null +++ b/templates/chat-resultat-transformer-stress.html @@ -0,0 +1,18 @@ +

+ {{alias}} transforme {{rolled.factor}}% de son stress +

+{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}} +{{#if rolled.isPart}} +
+ + Deuxième jet: {{rolled.second.roll}} {{rolled.second.quality}} + +
+{{/if}} +
+ + Transformation de {{perte}} points de stress sur {{stress}} + {{~#if (gt dissolution 0)}}; {{dissolution}} points perdus par la dissolution{{/if~}} + {{~#if (gt exaltation 0)}}; {{exaltation}} points gagnés par l'exaltation{{/if~}} + , gain de {{xp}} points d'expérience +