diff --git a/lang/fr.json b/lang/fr.json index 75a95d6..5726675 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -148,7 +148,10 @@ "fortune": "Utiliser la Fortune", "fortuneBonus": "1d8 + 8 au lieu de 2d8", "fortuneFixed": "Bonus fixe Fortune", - "usedFortune": "Fortune utilisée (1d8+8)" + "usedFortune": "Fortune utilisée (1d8+8)", + "puiser": "Puiser dans ses ressources", + "puiserDesc": "Ignore tous les malus — coche 1 case de Spleen", + "usedPuiser": "Ressources puisées — malus ignorés, +1 Spleen" }, "Moon": { "none": "Aucune phase", diff --git a/module/documents/roll.mjs b/module/documents/roll.mjs index 5dbd9d6..cd3c4a3 100644 --- a/module/documents/roll.mjs +++ b/module/documents/roll.mjs @@ -55,6 +55,7 @@ export class CelestopolRoll extends Roll { skillValue, woundMalus, woundLabel, + hasMalus: woundMalus < 0, difficultyChoices: SYSTEM.DIFFICULTY_CHOICES, defaultDifficulty: options.difficulty ?? "normal", destGaugeFull, @@ -95,17 +96,23 @@ export class CelestopolRoll extends Roll { if (!rollContext) return null - const difficulty = rollContext.difficulty ?? "normal" - const diffConfig = SYSTEM.DIFFICULTY_CHOICES[difficulty] ?? SYSTEM.DIFFICULTY_CHOICES.normal - const modifier = parseInt(rollContext.modifier ?? 0) || 0 - const aspectMod = parseInt(rollContext.aspectModifier ?? 0) || 0 - const useDestin = destGaugeFull && (rollContext.useDestin === true || rollContext.useDestin === "true") - const useFortune = fortuneValue > 0 && (rollContext.useFortune === true || rollContext.useFortune === "true") - const rollMoonDie = rollContext.rollMoonDie === true || rollContext.rollMoonDie === "true" + const difficulty = rollContext.difficulty ?? "normal" + const diffConfig = SYSTEM.DIFFICULTY_CHOICES[difficulty] ?? SYSTEM.DIFFICULTY_CHOICES.normal + const modifier = parseInt(rollContext.modifier ?? 0) || 0 + const aspectMod = parseInt(rollContext.aspectModifier ?? 0) || 0 + const useDestin = destGaugeFull && (rollContext.useDestin === true || rollContext.useDestin === "true") + const useFortune = fortuneValue > 0 && (rollContext.useFortune === true || rollContext.useFortune === "true") + const puiserRessources = rollContext.puiserRessources === true || rollContext.puiserRessources === "true" + const rollMoonDie = rollContext.rollMoonDie === true || rollContext.rollMoonDie === "true" + + // Puiser dans ses ressources → ignorer tous les malus + const effectiveWoundMalus = puiserRessources ? 0 : woundMalus + const effectiveModifier = puiserRessources ? Math.max(0, modifier) : modifier + const effectiveAspectMod = puiserRessources ? Math.max(0, aspectMod) : aspectMod // Fortune : 1d8 + 8 ; Destin : 3d8 ; sinon : 2d8 const nbDice = useDestin ? 3 : 2 - const totalModifier = skillValue + woundMalus + aspectMod + modifier + const totalModifier = skillValue + effectiveWoundMalus + effectiveAspectMod + effectiveModifier const formula = useFortune ? buildFormula(1, totalModifier + 8) : buildFormula(nbDice, totalModifier) @@ -125,10 +132,12 @@ export class CelestopolRoll extends Roll { ...options, difficulty, difficultyValue: diffConfig.value, - modifier, - aspectMod, + modifier: effectiveModifier, + aspectMod: effectiveAspectMod, + woundMalus: effectiveWoundMalus, useDestin, useFortune, + puiserRessources, nbDice: useFortune ? 1 : nbDice, formula, rollMode: rollContext.visibility ?? "publicroll", @@ -165,6 +174,19 @@ export class CelestopolRoll extends Roll { await actor.update({ "system.attributs.fortune.value": Math.max(0, currentFortune - 1) }) } + // Puiser dans ses ressources → coche une case de spleen + if (puiserRessources && actor) { + const currentSpleen = actor.system.spleen.lvl ?? 0 + if (currentSpleen < 8) { + const newLvl = currentSpleen + 1 + const key = `s${newLvl}` + await actor.update({ + "system.spleen.lvl": newLvl, + [`system.spleen.${key}.checked`]: true, + }) + } + } + // Mémoriser les préférences sur l'acteur if (actor) { await actor.update({ @@ -260,6 +282,7 @@ export class CelestopolRoll extends Roll { skillValue, useDestin: this.options.useDestin ?? false, useFortune: this.options.useFortune ?? false, + puiserRessources: this.options.puiserRessources ?? false, nbDice: this.options.nbDice ?? diceResults.length, woundMalus, woundLabel, diff --git a/styles/roll.less b/styles/roll.less index 817e566..1f51f57 100644 --- a/styles/roll.less +++ b/styles/roll.less @@ -285,6 +285,78 @@ .form-visibility label { color: #888; } + // ── Ligne Puiser dans ses ressources ── + .form-puiser-row { + border: 1px solid rgba(139,62,72,0.4); + border-radius: 4px; + background: rgba(107,30,40,0.06); + padding: 7px 10px; + + .puiser-toggle { + display: flex; + align-items: center; + gap: 8px; + cursor: pointer; + width: 100%; + + input[type="checkbox"] { + width: 16px; + height: 16px; + flex-shrink: 0; + appearance: none; + -webkit-appearance: none; + border: 2px solid rgba(139,62,72,0.6); + border-radius: 2px; + background: white; + cursor: pointer; + position: relative; + + &:checked { + background: var(--cel-accent, #6b1e28); + border-color: var(--cel-accent, #6b1e28); + &::after { + content: "✓"; + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.75em; + color: white; + } + } + } + + .puiser-icon { font-size: 1em; flex-shrink: 0; } + + .puiser-text { + flex: 1; + .puiser-main { + font-family: var(--cel-font-title, "CopaseticNF", serif); + font-size: 0.9em; + color: var(--cel-accent, #6b1e28); + display: block; + } + .puiser-sub { + font-size: 0.7em; + color: #888; + font-style: italic; + } + } + + .puiser-cost { + font-size: 0.8em; + font-weight: bold; + color: var(--cel-accent, #6b1e28); + background: rgba(107,30,40,0.1); + border: 1px solid rgba(139,62,72,0.35); + border-radius: 10px; + padding: 1px 8px; + white-space: nowrap; + } + } + } + // ── Ligne Fortune ── .form-fortune-row { border: 1px solid rgba(12,76,12,0.4); @@ -567,6 +639,13 @@ .used-fortune { font-weight: bold; color: var(--cel-green, #0c4c0c); } } + .used-info.used-puiser { + color: var(--cel-accent, #6b1e28); + background: rgba(107,30,40,0.08); + border-top-color: rgba(139,62,72,0.3); + font-style: italic; + } + // ── Fortune fixe badge dans zone dés ── .fortune-fixed-badge { display: inline-flex; diff --git a/templates/chat-message.hbs b/templates/chat-message.hbs index 3f40c32..74bb56d 100644 --- a/templates/chat-message.hbs +++ b/templates/chat-message.hbs @@ -84,6 +84,11 @@ ⚜ {{localize "CELESTOPOL.Roll.usedFortune"}} {{/if}} + {{#if puiserRessources}} +
+ 💪 {{localize "CELESTOPOL.Roll.usedPuiser"}} +
+ {{/if}} {{!-- Résultat du Dé de la Lune (narratif) --}} {{#if hasMoonDie}} diff --git a/templates/roll-dialog.hbs b/templates/roll-dialog.hbs index 8b24e7b..3b22cca 100644 --- a/templates/roll-dialog.hbs +++ b/templates/roll-dialog.hbs @@ -82,6 +82,21 @@ + {{!-- Puiser dans ses ressources — si malus de blessures --}} + {{#if hasMalus}} +
+ +
+ {{/if}} + {{!-- Fortune (1d8+8) — seulement si Fortune > 0 --}} {{#if fortuneValue}}
@@ -126,12 +141,17 @@ const woundMalus = {{woundMalus}}; function update() { - const modifier = parseInt(wrap.querySelector('#modifier')?.value ?? 0) || 0; - const aspectMod = parseInt(wrap.querySelector('#aspectModifier')?.value ?? 0) || 0; - const useDestin = wrap.querySelector('#useDestin')?.checked; - const useFortune= wrap.querySelector('#useFortune')?.checked; - const ndice = useDestin ? 3 : 2; - const totalMod = skillVal + woundMalus + modifier + aspectMod; + const modifier = parseInt(wrap.querySelector('#modifier')?.value ?? 0) || 0; + const aspectMod = parseInt(wrap.querySelector('#aspectModifier')?.value ?? 0) || 0; + const useDestin = wrap.querySelector('#useDestin')?.checked; + const useFortune = wrap.querySelector('#useFortune')?.checked; + const puiser = wrap.querySelector('#puiserRessources')?.checked; + const ndice = useDestin ? 3 : 2; + + const effWound = puiser ? 0 : woundMalus; + const effMod = puiser ? Math.max(0, modifier) : modifier; + const effAspect = puiser ? Math.max(0, aspectMod) : aspectMod; + const totalMod = skillVal + effWound + effMod + effAspect; let formula; if (useFortune) { @@ -147,7 +167,7 @@ if (previewEl) previewEl.textContent = formula; } - wrap.querySelectorAll('#modifier, #aspectModifier, #useDestin, #useFortune').forEach(el => { + wrap.querySelectorAll('#modifier, #aspectModifier, #useDestin, #useFortune, #puiserRessources').forEach(el => { el.addEventListener('change', update); el.addEventListener('input', update); });