From 74515d28f432da0744aecca390fe20c62d2ffe30 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Mon, 22 Sep 2025 16:18:29 +0200 Subject: [PATCH] =?UTF-8?q?Am=C3=A9lioration=20de=20la=20gestion=20de=20la?= =?UTF-8?q?=20surprise?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- changelog.md | 12 +++-- css/foundryvtt-reve-de-dragon.css | 3 ++ less/roll-dialog.less | 5 +- module/rdd-combat.js | 12 +++-- module/rdd-resolution-table.js | 44 +++------------- module/roll/roll-basic-parts.mjs | 27 ++++++++++ module/roll/roll-dialog.mjs | 6 +-- module/roll/roll-part-attaque.mjs | 23 ++++----- module/roll/roll-part-defense.mjs | 5 +- module/roll/roll-part-sign.mjs | 22 ++------ templates/chat-demande-defense.hbs | 75 ++++++++++++++-------------- templates/roll/roll-button.hbs | 8 +++ templates/roll/roll-part-attaque.hbs | 12 ++--- templates/roll/roll-part-defense.hbs | 6 +-- 14 files changed, 129 insertions(+), 131 deletions(-) diff --git a/changelog.md b/changelog.md index 33cc1758..5fb048db 100644 --- a/changelog.md +++ b/changelog.md @@ -3,19 +3,23 @@ ## 13.0.9 - Le combat d'Illysis - Fix - La montée en TMR fonctionne +- ajout d'un status "Force insuffisante" - Nouvelle fenêtre de jets de dés + - ajout du statut "Force insuffisante" aux acteurs si la + force est insuffisante pour l'arme - avancement du mode attaque - choix de tactique - - choix des dommages mortel/non-mortel, affichage + - choix mortel/non-mortel pour les dommages + - affichage des dommages ajustés delon les choix - affichage du statut de surprise de l'attaquant - affichage du statut de surprise du défenseur - - prise en compte des significatives (force insuffisante, demi-surprises) + - prise en compte des significatives (demi-surprises) - avancement du mode défense - sélection esquive/parade - affichage du statut de surprise du défenseur - prise en compte des significatives (demi-surprises, armes disparates, - force insuffisante, particulière en finesse) - + particulière en finesse) + - impossible de faire un jet "actif" en surprise totale (attaque, parade, ...) ## 13.0.8 - Le renouveau d'Illysis diff --git a/css/foundryvtt-reve-de-dragon.css b/css/foundryvtt-reve-de-dragon.css index a203b46f..5baad793 100644 --- a/css/foundryvtt-reve-de-dragon.css +++ b/css/foundryvtt-reve-de-dragon.css @@ -564,6 +564,9 @@ select, .system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline span.status-surprise img { filter: invert(0.8); } +.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline label { + align-content: center; +} .system-foundryvtt-reve-de-dragon .roll-dialog roll-section selected-numeric-value { display: flow; width: 2.5rem; diff --git a/less/roll-dialog.less b/less/roll-dialog.less index c550aeb6..9b65c7ef 100644 --- a/less/roll-dialog.less +++ b/less/roll-dialog.less @@ -95,7 +95,7 @@ display: flex; flex-direction: column; grid-area: img; - img{ + img { border: 0; padding: 1px; max-height: 3rem; @@ -126,6 +126,9 @@ filter: invert(0.8); } } + label { + align-content: center; + } } } } diff --git a/module/rdd-combat.js b/module/rdd-combat.js index 2f858307..142795ef 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -567,6 +567,9 @@ export class RdDCombat { /* -------------------------------------------- */ static isParticuliere(rollData) { + if (rollData.ids) { + return rollData.rolled.isPart + } if (!rollData.attackerRoll && rollData.ajustements.surprise.used) { return false; } @@ -575,6 +578,9 @@ export class RdDCombat { /* -------------------------------------------- */ static isReussite(rollData) { + if (rollData.ids) { + return rollData.rolled.is + } switch (rollData.ajustements.surprise.used) { case 'totale': return false; case 'demi': return rollData.rolled.isSign; @@ -971,14 +977,14 @@ export class RdDCombat { await RollDialog.create(rollData, { onRoll: (dialog) => { - this._onCloseRollDialog(), - dialog.close() + dialog.close() }, customChatMessage: true, callbacks: [async (actor, rd) => { this.removeChatMessageActionsPasseArme(rd.passeArme) // defense: esquive / arme de parade / competence de défense - await rd.active.actor.incDecItemUse(rd.current[PART_DEFENSE].defense?.id, !RdDCombat.isParticuliere(rd)) + if (!RdDCombat.isParticuliere(rd)) + await rd.active.actor.incDecItemUse(rd.current[PART_DEFENSE].defense?.id, ) await this._onDefenseV2(rd) }] }) diff --git a/module/rdd-resolution-table.js b/module/rdd-resolution-table.js index f750c47f..83d5b783 100644 --- a/module/rdd-resolution-table.js +++ b/module/rdd-resolution-table.js @@ -184,47 +184,15 @@ export class RdDResolutionTable { return Math.max(Math.floor(carac * (diff + 10) / 2), 1); } - /* -------------------------------------------- */ - static isEchec(rollData) { - switch (rollData.surprise) { - case 'demi': return !rollData.rolled.isSign; - case 'totale': return true; - } - return rollData.rolled.isEchec; - } - - /* -------------------------------------------- */ - static isEchecTotal(rollData) { - if (rollData.arme && rollData.surprise == 'demi') { - return rollData.rolled.isEchec; - } - return rollData.rolled.isETotal; - } - - /* -------------------------------------------- */ - static isParticuliere(rollData) { - if (rollData.arme && rollData.surprise) { - return false; - } - return rollData.rolled.isPart; - } - - /* -------------------------------------------- */ - static isReussite(rollData) { - switch (rollData.surprise) { - case 'demi': return rollData.rolled.isSign; - case 'totale': return false; - } - return rollData.rolled.isSuccess; - } - /* -------------------------------------------- */ static computeReussite(chances, roll, diviseur) { - const reussite = reussites.find(x => x.condition(chances, roll)); - if (diviseur > 1 && reussite.code == 'norm') { - return reussiteInsuffisante; + const reussite = reussites.find(x => x.condition(chances, roll)) + if (diviseur > 1 && reussite.isSuccess) { + if (chances > roll * diviseur){ + return reussiteInsuffisante + } } - return reussite; + return reussite } /* -------------------------------------------- */ diff --git a/module/roll/roll-basic-parts.mjs b/module/roll/roll-basic-parts.mjs index b395d6da..9df53847 100644 --- a/module/roll/roll-basic-parts.mjs +++ b/module/roll/roll-basic-parts.mjs @@ -1,4 +1,8 @@ import { ActorToken } from "../actor-token.mjs" +import { StatusEffects } from "../settings/status-effects.js" +import { ROLL_MODE_ATTAQUE, ROLL_MODE_DEFENSE } from "./roll-constants.mjs" +import { PART_ATTAQUE } from "./roll-part-attaque.mjs" +import { PART_DEFENSE } from "./roll-part-defense.mjs" export class RollBasicParts { @@ -11,6 +15,29 @@ export class RollBasicParts { } } + loadSurprises(rollData, mode) { + if (!rollData.mode.passif) { + this.loadSurprise(rollData.active, this.getForceRequiseActiveActor(rollData, mode)) + this.loadSurprise(rollData.opponent, 0) + } + } + + loadSurprise(who, forceRequise) { + if (who?.actor) { + foundry.utils.mergeObject(who, + StatusEffects.getActorEffetSurprise(who.actor, forceRequise), + { overwrite: true, inPlace: true }) + } + } + + getForceRequiseActiveActor(rollData, mode) { + switch (mode) { + case ROLL_MODE_ATTAQUE: return rollData.current[PART_ATTAQUE].attaque.forceRequise + case ROLL_MODE_DEFENSE: return rollData.current[PART_DEFENSE].forceRequise + default: return 0 + } + } + initFrom(rollData) { return { selected: {}, diff --git a/module/roll/roll-dialog.mjs b/module/roll/roll-dialog.mjs index 73522b3c..561c9221 100644 --- a/module/roll/roll-dialog.mjs +++ b/module/roll/roll-dialog.mjs @@ -217,7 +217,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 }) } - + static async create(rollData, rollOptions = {}) { const rollDialog = new RollDialog(rollData, rollOptions) rollDialog.render(true) @@ -250,9 +250,6 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 constructor(rollData, rollOptions) { super() this.rollData = rollData - // const callbacks = this.rollOptions.callbacks.map(c => - // r => r.activve.actor Promise.all(this.rollOptions.callbacks.map(async callback => await callback(rollData.active.actor, rollData))) - // ) this.rollOptions = { callbacks: [ async (actor, r) => await actor.appliquerAjoutExperience(r), @@ -361,6 +358,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 const modes = ROLL_MODE_TABS.filter(m => m.isAllowed(rollData) && m.visible(rollData)) .map(m => m.toModeData(rollData)) + BASIC_PARTS.loadSurprises(this.rollData, this.getSelectedMode().code) this.setModeTitle() const visibleRollParts = this.getActiveParts() diff --git a/module/roll/roll-part-attaque.mjs b/module/roll/roll-part-attaque.mjs index 6b69abc9..32ba51d2 100644 --- a/module/roll/roll-part-attaque.mjs +++ b/module/roll/roll-part-attaque.mjs @@ -41,25 +41,25 @@ export class RollPartAttaque extends RollPartSelect { prepareContext(rollData) { const current = this.getCurrent(rollData) - current.defenseur = StatusEffects.getActorEffetSurprise(rollData.opponent?.actor, 0) - current.attaquant = StatusEffects.getActorEffetSurprise(rollData.active.actor, current.attaque.forceRequise) current.dmg = this.$dmgRollV2(rollData, current) } $dmgRollV2(rollData, current) { const actor = rollData.active.actor - const defender = rollData.opponent?.actor - const dmgArme = RdDBonus.dmgArme(current.attaque.arme, current.attaque.dommagesArme) + const attaque = current.attaque + const arme = attaque.arme + const dmgArme = RdDBonus.dmgArme(arme, attaque.dommagesArme) + const dmg = { total: 0, dmgArme: dmgArme, - penetration: current.attaque.arme.penetration(), + penetration: arme.penetration(), dmgTactique: current.tactique?.dmg ?? 0, dmgParticuliere: 0, // TODO RdDBonus._dmgParticuliere(rollData), - dmgSurprise: current.surpriseDefenseur?.dmg ?? 0, - mortalite: RdDBonus.mortalite(current.dmg?.mortalite, current.attaque.arme.system.mortalite, defender?.isEntite()), - dmgActor: RdDBonus.bonusDmg(actor, current.attaque.carac.key, dmgArme, current.attaque.forceRequise), - dmgForceInsuffisante: Math.min(0, actor.getForce() - current.attaque.forceRequise) + dmgSurprise: rollData.opponent?.surprise?.dmg ?? 0, + mortalite: RdDBonus.mortalite(current.dmg?.mortalite, arme.system.mortalite, rollData.opponent?.actor?.isEntite()), + dmgActor: RdDBonus.bonusDmg(actor, attaque.carac.key, dmgArme, attaque.forceRequise), + dmgForceInsuffisante: Math.min(0, actor.getForce() - attaque.forceRequise) } dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere + dmg.dmgForceInsuffisante return dmg @@ -71,8 +71,8 @@ export class RollPartAttaque extends RollPartSelect { if (current.tactique) { ajustements.push({ label: current.tactique.label, diff: current.tactique.attaque }) } - if (current.surpriseDefenseur) { - ajustements.push({ label: current.surpriseDefenseur.label, diff: current.surpriseDefenseur.attaque }) + if (rollData.opponent?.surprise) { + ajustements.push({ label: rollData.opponent.surprise.label, diff: rollData.opponent.surprise.attaque }) } return ajustements } @@ -115,7 +115,6 @@ export class RollPartAttaque extends RollPartSelect { switch (part.code) { case PART_CARAC: return part.filterCaracs(rollData, [current.attaque.carac.key]) case PART_COMP: return part.filterComps(rollData, [current.attaque.comp?.name]) - case PART_SIGN: return part.setArme(rollData, current.attaque.forceRequise, false) } } return undefined diff --git a/module/roll/roll-part-defense.mjs b/module/roll/roll-part-defense.mjs index 94c9d164..cd40a957 100644 --- a/module/roll/roll-part-defense.mjs +++ b/module/roll/roll-part-defense.mjs @@ -69,9 +69,6 @@ export class RollPartDefense extends RollPartSelect { } prepareContext(rollData) { - const current = this.getCurrent(rollData) - current.defenseur = StatusEffects.getActorEffetSurprise(rollData.active.actor, current.forceRequise) - // current.dmg = this.$dmgRollV2(rollData, current) } @@ -104,7 +101,7 @@ export class RollPartDefense extends RollPartSelect { case PART_CARAC: return part.filterCaracs(rollData, [current.carac]) case PART_COMP: return part.filterComps(rollData, [current.comp?.name]) case PART_DIFF: return part.setDiff(rollData, this.getDiffDefense(rollData)) - case PART_SIGN: return part.setArme(rollData, current.forceRequise, this.isArmeDisparate(rollData)) + case PART_SIGN: return part.setArmeDisparate(rollData, this.isArmeDisparate(rollData)) } } return undefined diff --git a/module/roll/roll-part-sign.mjs b/module/roll/roll-part-sign.mjs index 4a88fb95..a4219ea4 100644 --- a/module/roll/roll-part-sign.mjs +++ b/module/roll/roll-part-sign.mjs @@ -39,8 +39,7 @@ export class RollPartSign extends RollPart { const isCombat = this.isCombat(rollData) const current = this.getCurrent(rollData) current.armeDisparate = isCombat && current.armeDisparate - current.forceRequise = current.forceRequise ?? 0 - current.surprise = actor.getSurprise(isCombat) + current.surprise = actor.getSurprise(isCombat) // TODO: could be from rollData.active.surprise?? current.reasons = actor.getEffects(it => StatusEffects.niveauSurprise(it) > 0).map(it => it.name) current.diviseur = 1 if (current.surprise == 'demi') { @@ -53,10 +52,6 @@ export class RollPartSign extends RollPart { current.diviseur *= 2 current.reasons.push('Armes disparates') } - if (this.isForceInsuffisante(actor, current)) { - current.diviseur *= 2 - current.reasons.push('Force insuffisante') - } if (this.isAttaqueFinesse(rollData)) { current.diviseur *= 2 current.reasons.push('Particulière en finesse') @@ -73,15 +68,6 @@ export class RollPartSign extends RollPart { return ROLL_MODE_DEFENSE == rollData.mode.current && rollData.attaque.particuliere == 'finesse' } - isForceInsuffisante(actor, current) { - if (actor?.isPersonnage()) { - const requise = current.forceRequise - const force = parseInt(actor.system.carac.force.value) - return requise > force - } - return false - } - isParadeArmeDisparate(current) { return current.armeDisparate } @@ -106,9 +92,7 @@ export class RollPartSign extends RollPart { }) } - setArme(rollData, forceRequise, armeDisparate) { - const current = this.getCurrent(rollData) - current.armeDisparate = armeDisparate - current.forceRequise = forceRequise + setArmeDisparate(rollData, armeDisparate) { + this.getCurrent(rollData).armeDisparate = armeDisparate } } \ No newline at end of file diff --git a/templates/chat-demande-defense.hbs b/templates/chat-demande-defense.hbs index 54456596..6a813946 100644 --- a/templates/chat-demande-defense.hbs +++ b/templates/chat-demande-defense.hbs @@ -49,45 +49,46 @@ {{/if}}
- {{/if}} - {{#each armes as |arme key|}} - - Parer avec {{arme.name}} - {{#if (or (eq ../attaqueCategorie 'tir') (eq ../attaqueCategorie 'lancer'))}} - (difficulté à déterminer) - {{else}}à {{../diffLibre }} - {{/if}} - {{#if (eq arme.typeParade 'sign')}} - ×½ - {{/if}} - {{#if arme.nbUsage}}(Utilisations : {{arme.nbUsage}}){{/if}} - -
+ {{else}} + {{#each armes as |arme key|}} + + Parer avec {{arme.name}} + {{#if (or (eq ../attaqueCategorie 'tir') (eq ../attaqueCategorie 'lancer'))}} + (difficulté à déterminer) + {{else}}à {{../diffLibre }} + {{/if}} + {{#if (eq arme.typeParade 'sign')}} + ×½ + {{/if}} + {{#if arme.nbUsage}}(Utilisations : {{arme.nbUsage}}){{/if}} + +
{{/each}} {{#if mainsNues}} - - Parer à mains nues à {{diffLibre}}{{#if arme.nbUsage}} (Utilisations : {{arme.nbUsage}}){{/if}} - -
- {{/if}} - {{#if (ne attaqueCategorie 'tir')}} - {{#each esquives as |esquive key|}} - - {{esquive.name}} - {{#if (or (eq ../attaqueCategorie 'tir') (eq ../attaqueCategorie 'lancer'))}} - (difficulté à déterminer) - {{else}}à {{../diffLibre }} - {{/if}} - {{#if esquive.nbUsage}}(Utilisations : {{esquive.nbUsage}}){{/if}} - -
- {{/each}} + + Parer à mains nues à {{diffLibre}}{{#if arme.nbUsage}} (Utilisations : {{arme.nbUsage}}){{/if}} + +
+ {{/if}} + {{#if (ne attaqueCategorie 'tir')}} + {{#each esquives as |esquive key|}} + + {{esquive.name}} + {{#if (or (eq ../attaqueCategorie 'tir') (eq ../attaqueCategorie 'lancer'))}} + (difficulté à déterminer) + {{else}}à {{../diffLibre }} + {{/if}} + {{#if esquive.nbUsage}}(Utilisations : {{esquive.nbUsage}}){{/if}} + +
+ {{/each}} + {{/if}} {{/if}} {{/if}} {{/unless}} diff --git a/templates/roll/roll-button.hbs b/templates/roll/roll-button.hbs index 8a25d8ac..396b69c8 100644 --- a/templates/roll/roll-button.hbs +++ b/templates/roll/roll-button.hbs @@ -1,6 +1,14 @@ +{{#if (or rollData.mode.passif (ne rollData.active.surprise.key 'totale'))}} +{{else}} + +{{/if}} \ No newline at end of file diff --git a/templates/roll/roll-part-attaque.hbs b/templates/roll/roll-part-attaque.hbs index f66b5529..9b4d4d53 100644 --- a/templates/roll/roll-part-attaque.hbs +++ b/templates/roll/roll-part-attaque.hbs @@ -28,22 +28,22 @@ {{/if}} - {{#if current.attaquant.effets}} + {{#if rollData.active.effets}} - Attaquant en {{lowerFirst current.attaquant.surprise.label}}:  - {{#each current.attaquant.effets as |effect|}} + Attaquant en {{lowerFirst rollData.active.surprise.label}}:  + {{#each rollData.active.effets as |effect|}} {{localize effect.name}} {{/each}} {{/if}} - {{#if current.defenseur.surprise}} + {{#if rollData.opponent.surprise}} - Defenseur en {{lowerFirst current.defenseur.surprise.label}}:  - {{#each current.defenseur.effets as |effect|}} + Defenseur en {{lowerFirst rollData.opponent.surprise.label}}:  + {{#each rollData.opponent.effets as |effect|}} {{localize effect.name}} {{/each}} diff --git a/templates/roll/roll-part-defense.hbs b/templates/roll/roll-part-defense.hbs index 88b0758c..f934f24a 100644 --- a/templates/roll/roll-part-defense.hbs +++ b/templates/roll/roll-part-defense.hbs @@ -7,11 +7,11 @@ {{selectOptions refs.defenses selected=current.key valueAttr="key" labelAttr="label"}} - {{#if current.defenseur.effets}} + {{#if rollData.active.effets}} - Defense en {{lowerFirst current.defenseur.surprise.label}}:  - {{#each current.defenseur.effets as |effect|}} + Defense en {{lowerFirst rollData.active.surprise.label}}:  + {{#each rollData.active.effets as |effect|}} {{localize effect.name}} {{/each}}