1.5.1 : potions en D3 et jet unique par fiole, retrait de « (jet) » dans les effets
- Sang de Toh Réroh et PufPuff passent de D6 à D3 (conformes à Mountypedia) - Un seul jet de XD3 par potion : le même total s'applique à ATT et ESQ (Corruption, Rhume/Grippe/Pneumonie, PufPuff, Sang de Toh Réroh, Zet Crakdedand) - Panneau des effets : suppression des mentions « (jet) » et « (jets inclus) » - APP_VERSION réalignée sur le README (1.5.1) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -152,6 +152,11 @@ non affilié au jeu original de Mountyhall SARL.
|
|||||||
|
|
||||||
## Versions
|
## Versions
|
||||||
|
|
||||||
|
- **1.5.1** (2026-06-11) — Potions fidèles à Mountypedia : toutes les potions à jet
|
||||||
|
utilisent des D3 (Sang de Toh Réroh et PufPuff étaient à tort en D6), et chaque
|
||||||
|
fiole ne fait qu'un seul jet — le même total s'applique à toutes les caracs
|
||||||
|
concernées (ex. Sang de Toh Réroh niv. 4 : un jet de 4D3 partagé par ATT et ESQ).
|
||||||
|
Affichage : suppression des mentions « (jet) » dans le panneau des effets.
|
||||||
- **1.5.0** (2026-06-11) — Page « Règles des talents » : les 10 fiches compétences/
|
- **1.5.0** (2026-06-11) — Page « Règles des talents » : les 10 fiches compétences/
|
||||||
sortilèges au format MountyHall (coût, type, jet de résistance, formules, lore),
|
sortilèges au format MountyHall (coût, type, jet de résistance, formules, lore),
|
||||||
avec encart « Mes infos » en partie (maîtrise, taux de réussite, jets calculés du
|
avec encart « Mes infos » en partie (maîtrise, taux de réussite, jets calculés du
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const APP_VERSION = "0.1.6";
|
const APP_VERSION = "1.5.1";
|
||||||
|
|
||||||
/* Alpha : maîtrise initiale haute pour les tests. Remettre 15 % / 15 % à la v1.0 officielle. */
|
/* Alpha : maîtrise initiale haute pour les tests. Remettre 15 % / 15 % à la v1.0 officielle. */
|
||||||
const START_COMP_PCT = 90;
|
const START_COMP_PCT = 90;
|
||||||
|
|||||||
+37
-30
@@ -25,10 +25,10 @@ function corruptionYZ(x) {
|
|||||||
return { y: potRand(16, 30), z: potRand(16, 30) };
|
return { y: potRand(16, 30), z: potRand(16, 30) };
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Jet de modificateur potion : X D6/D3 → bonus/malus fixe sur les jets (pas sur le nb de dés). */
|
/* Modificateur de potion : un seul jet de X D3 par fiole, le même total
|
||||||
function rollMod(rollDice, count, faces, negative = false) {
|
* s'applique à toutes les caracs concernées (ATT, ESQ…). */
|
||||||
const r = rollDice(count, faces);
|
function sharedMod(total, count, faces, negative = false) {
|
||||||
const value = negative ? -r.total : r.total;
|
const value = negative ? -total : total;
|
||||||
const sign = negative ? "−" : "+";
|
const sign = negative ? "−" : "+";
|
||||||
return {
|
return {
|
||||||
value,
|
value,
|
||||||
@@ -85,8 +85,9 @@ const POTION_DEFS = {
|
|||||||
rollPower: () => potRand(3, 7),
|
rollPower: () => potRand(3, 7),
|
||||||
build(_t, p, rollDice) {
|
build(_t, p, rollDice) {
|
||||||
const { y, z } = corruptionYZ(p);
|
const { y, z } = corruptionYZ(p);
|
||||||
const attR = rollMod(rollDice, p, 3, false);
|
const jet = rollDice(p, 3).total;
|
||||||
const esqR = rollMod(rollDice, p, 3, true);
|
const attR = sharedMod(jet, p, 3, false);
|
||||||
|
const esqR = sharedMod(jet, p, 3, true);
|
||||||
const lines = [`ATT ${attR.line}`, `ESQ ${esqR.line}`, `DEG +${p}`, `REG −${p}`, `VUE −${p}`, `Armure +${p}`];
|
const lines = [`ATT ${attR.line}`, `ESQ ${esqR.line}`, `DEG +${p}`, `REG −${p}`, `VUE −${p}`, `Armure +${p}`];
|
||||||
return {
|
return {
|
||||||
log: `Elixir de Corruption : ${lines.join(", ")} ; RM −${y} %, MM −${z} % (5 tours).`,
|
log: `Elixir de Corruption : ${lines.join(", ")} ; RM −${y} %, MM −${z} % (5 tours).`,
|
||||||
@@ -101,7 +102,7 @@ const POTION_DEFS = {
|
|||||||
duration: 5,
|
duration: 5,
|
||||||
rollPower: () => potRand(3, 7),
|
rollPower: () => potRand(3, 7),
|
||||||
build(_t, p, rollDice) {
|
build(_t, p, rollDice) {
|
||||||
const attR = rollMod(rollDice, p, 3, false);
|
const attR = sharedMod(rollDice(p, 3).total, p, 3, false);
|
||||||
const lines = [`ATT ${attR.line}`, `DEG +${p}`];
|
const lines = [`ATT ${attR.line}`, `DEG +${p}`];
|
||||||
return {
|
return {
|
||||||
log: `Elixir de Fertilité : ${lines.join(", ")} pendant 5 tours.`,
|
log: `Elixir de Fertilité : ${lines.join(", ")} pendant 5 tours.`,
|
||||||
@@ -114,7 +115,7 @@ const POTION_DEFS = {
|
|||||||
duration: 5,
|
duration: 5,
|
||||||
rollPower: () => potRand(3, 7),
|
rollPower: () => potRand(3, 7),
|
||||||
build(_t, p, rollDice) {
|
build(_t, p, rollDice) {
|
||||||
const esqR = rollMod(rollDice, p, 3, false);
|
const esqR = sharedMod(rollDice(p, 3).total, p, 3, false);
|
||||||
const lines = [`ESQ ${esqR.line}`, `VUE +${p}`];
|
const lines = [`ESQ ${esqR.line}`, `VUE +${p}`];
|
||||||
return {
|
return {
|
||||||
log: `Elixir de Feu : ${lines.join(", ")} pendant 5 tours.`,
|
log: `Elixir de Feu : ${lines.join(", ")} pendant 5 tours.`,
|
||||||
@@ -189,8 +190,9 @@ const POTION_DEFS = {
|
|||||||
duration: 3,
|
duration: 3,
|
||||||
rollPower: () => potRand(1, 2),
|
rollPower: () => potRand(1, 2),
|
||||||
build(_t, p, rollDice) {
|
build(_t, p, rollDice) {
|
||||||
const attR = rollMod(rollDice, p, 3, true);
|
const jet = rollDice(p, 3).total;
|
||||||
const esqR = rollMod(rollDice, p, 3, true);
|
const attR = sharedMod(jet, p, 3, true);
|
||||||
|
const esqR = sharedMod(jet, p, 3, true);
|
||||||
const lines = [`ATT ${attR.line}`, `ESQ ${esqR.line}`, `DEG −${p}`, `REG −${p}`];
|
const lines = [`ATT ${attR.line}`, `ESQ ${esqR.line}`, `DEG −${p}`, `REG −${p}`];
|
||||||
return {
|
return {
|
||||||
log: `Rhume en Conserve : ${lines.join(", ")} pendant 3 tours.`,
|
log: `Rhume en Conserve : ${lines.join(", ")} pendant 3 tours.`,
|
||||||
@@ -205,8 +207,9 @@ const POTION_DEFS = {
|
|||||||
duration: 3,
|
duration: 3,
|
||||||
rollPower: () => potRand(3, 4),
|
rollPower: () => potRand(3, 4),
|
||||||
build(_t, p, rollDice) {
|
build(_t, p, rollDice) {
|
||||||
const attR = rollMod(rollDice, p, 3, true);
|
const jet = rollDice(p, 3).total;
|
||||||
const esqR = rollMod(rollDice, p, 3, true);
|
const attR = sharedMod(jet, p, 3, true);
|
||||||
|
const esqR = sharedMod(jet, p, 3, true);
|
||||||
const lines = [`ATT ${attR.line}`, `ESQ ${esqR.line}`, `DEG −${p}`, `REG −${p}`];
|
const lines = [`ATT ${attR.line}`, `ESQ ${esqR.line}`, `DEG −${p}`, `REG −${p}`];
|
||||||
return {
|
return {
|
||||||
log: `Grippe en Conserve : ${lines.join(", ")} pendant 3 tours.`,
|
log: `Grippe en Conserve : ${lines.join(", ")} pendant 3 tours.`,
|
||||||
@@ -221,8 +224,9 @@ const POTION_DEFS = {
|
|||||||
duration: 3,
|
duration: 3,
|
||||||
rollPower: () => 5,
|
rollPower: () => 5,
|
||||||
build(_t, _p, rollDice) {
|
build(_t, _p, rollDice) {
|
||||||
const attR = rollMod(rollDice, 5, 3, true);
|
const jet = rollDice(5, 3).total;
|
||||||
const esqR = rollMod(rollDice, 5, 3, true);
|
const attR = sharedMod(jet, 5, 3, true);
|
||||||
|
const esqR = sharedMod(jet, 5, 3, true);
|
||||||
const lines = [`ATT ${attR.line}`, `ESQ ${esqR.line}`, "DEG −5", "REG −5"];
|
const lines = [`ATT ${attR.line}`, `ESQ ${esqR.line}`, "DEG −5", "REG −5"];
|
||||||
return {
|
return {
|
||||||
log: `Pneumonie en Conserve : ${lines.join(", ")} pendant 3 tours.`,
|
log: `Pneumonie en Conserve : ${lines.join(", ")} pendant 3 tours.`,
|
||||||
@@ -294,8 +298,9 @@ const POTION_DEFS = {
|
|||||||
duration: 3,
|
duration: 3,
|
||||||
rollPower: () => potRand(0, 2),
|
rollPower: () => potRand(0, 2),
|
||||||
build(troll, p, rollDice) {
|
build(troll, p, rollDice) {
|
||||||
const attR = p > 0 ? rollMod(rollDice, p, 6, true) : { value: 0, line: "ATT ±0" };
|
const jet = p > 0 ? rollDice(p, 3).total : 0;
|
||||||
const esqR = p > 0 ? rollMod(rollDice, p, 6, true) : { value: 0, line: "ESQ ±0" };
|
const attR = p > 0 ? sharedMod(jet, p, 3, true) : { value: 0, line: "±0" };
|
||||||
|
const esqR = p > 0 ? sharedMod(jet, p, 3, true) : { value: 0, line: "±0" };
|
||||||
const y = p >= 2 ? rollDice(2, 3).total : 0;
|
const y = p >= 2 ? rollDice(2, 3).total : 0;
|
||||||
if (y > 0) troll.pv = Math.max(1, troll.pv - y);
|
if (y > 0) troll.pv = Math.max(1, troll.pv - y);
|
||||||
const lines = [`ATT ${attR.line}`, `ESQ ${esqR.line}`, `VUE −${p + 1}`];
|
const lines = [`ATT ${attR.line}`, `ESQ ${esqR.line}`, `VUE −${p + 1}`];
|
||||||
@@ -313,8 +318,9 @@ const POTION_DEFS = {
|
|||||||
duration: 4,
|
duration: 4,
|
||||||
rollPower: () => potRand(1, 5),
|
rollPower: () => potRand(1, 5),
|
||||||
build(_t, p, rollDice) {
|
build(_t, p, rollDice) {
|
||||||
const attR = rollMod(rollDice, p, 6, false);
|
const jet = rollDice(p, 3).total;
|
||||||
const esqR = rollMod(rollDice, p, 6, false);
|
const attR = sharedMod(jet, p, 3, false);
|
||||||
|
const esqR = sharedMod(jet, p, 3, false);
|
||||||
const lines = [`ATT ${attR.line}`, `ESQ ${esqR.line}`, `VUE +${p}`];
|
const lines = [`ATT ${attR.line}`, `ESQ ${esqR.line}`, `VUE +${p}`];
|
||||||
return {
|
return {
|
||||||
log: `Sang de Toh Réroh : ${lines.join(", ")} pendant 4 tours.`,
|
log: `Sang de Toh Réroh : ${lines.join(", ")} pendant 4 tours.`,
|
||||||
@@ -363,8 +369,9 @@ const POTION_DEFS = {
|
|||||||
duration: 3,
|
duration: 3,
|
||||||
rollPower: () => potRand(1, 5),
|
rollPower: () => potRand(1, 5),
|
||||||
build(troll, p, rollDice) {
|
build(troll, p, rollDice) {
|
||||||
const attR = rollMod(rollDice, p, 3, true);
|
const jet = rollDice(p, 3).total;
|
||||||
const esqR = rollMod(rollDice, p, 3, true);
|
const attR = sharedMod(jet, p, 3, true);
|
||||||
|
const esqR = sharedMod(jet, p, 3, true);
|
||||||
const heal = rollDice(p, 3).total;
|
const heal = rollDice(p, 3).total;
|
||||||
troll.pv = Math.min(troll.pvMax, troll.pv + heal);
|
troll.pv = Math.min(troll.pvMax, troll.pv + heal);
|
||||||
const lines = [`ATT ${attR.line}`, `ESQ ${esqR.line}`, `VUE −${p}`, `PV +${heal} (${p}D3)`];
|
const lines = [`ATT ${attR.line}`, `ESQ ${esqR.line}`, `VUE −${p}`, `PV +${heal} (${p}D3)`];
|
||||||
@@ -499,10 +506,10 @@ const EFFECT_MOD_LABELS = {
|
|||||||
function formatEffectMods(effect) {
|
function formatEffectMods(effect) {
|
||||||
if (effect.modLines?.length) return [...effect.modLines];
|
if (effect.modLines?.length) return [...effect.modLines];
|
||||||
const parts = [];
|
const parts = [];
|
||||||
if (effect.attFlat) parts.push(`ATT ${effect.attFlat > 0 ? "+" : ""}${effect.attFlat} (jet)`);
|
if (effect.attFlat) parts.push(`ATT ${effect.attFlat > 0 ? "+" : ""}${effect.attFlat}`);
|
||||||
if (effect.esqFlat) parts.push(`ESQ ${effect.esqFlat > 0 ? "+" : ""}${effect.esqFlat} (jet)`);
|
if (effect.esqFlat) parts.push(`ESQ ${effect.esqFlat > 0 ? "+" : ""}${effect.esqFlat}`);
|
||||||
if (effect.degFlat) parts.push(`DEG ${effect.degFlat > 0 ? "+" : ""}${effect.degFlat} (jet)`);
|
if (effect.degFlat) parts.push(`DEG ${effect.degFlat > 0 ? "+" : ""}${effect.degFlat}`);
|
||||||
if (effect.regFlat) parts.push(`REG ${effect.regFlat > 0 ? "+" : ""}${effect.regFlat} (jet)`);
|
if (effect.regFlat) parts.push(`REG ${effect.regFlat > 0 ? "+" : ""}${effect.regFlat}`);
|
||||||
for (const [key, label] of Object.entries(EFFECT_MOD_LABELS)) {
|
for (const [key, label] of Object.entries(EFFECT_MOD_LABELS)) {
|
||||||
const v = effect[key];
|
const v = effect[key];
|
||||||
if (typeof v !== "number" || !v) continue;
|
if (typeof v !== "number" || !v) continue;
|
||||||
@@ -562,10 +569,10 @@ function renderEffectsPanel(troll) {
|
|||||||
|
|
||||||
const total = sumPotionMods(troll.potionEffects);
|
const total = sumPotionMods(troll.potionEffects);
|
||||||
const totalLines = [];
|
const totalLines = [];
|
||||||
if (total.attFlat) totalLines.push(`ATT ${total.attFlat > 0 ? "+" : ""}${total.attFlat} (jet)`);
|
if (total.attFlat) totalLines.push(`ATT ${total.attFlat > 0 ? "+" : ""}${total.attFlat}`);
|
||||||
if (total.esqFlat) totalLines.push(`ESQ ${total.esqFlat > 0 ? "+" : ""}${total.esqFlat} (jet)`);
|
if (total.esqFlat) totalLines.push(`ESQ ${total.esqFlat > 0 ? "+" : ""}${total.esqFlat}`);
|
||||||
if (total.degFlat) totalLines.push(`DEG ${total.degFlat > 0 ? "+" : ""}${total.degFlat} (jet)`);
|
if (total.degFlat) totalLines.push(`DEG ${total.degFlat > 0 ? "+" : ""}${total.degFlat}`);
|
||||||
if (total.regFlat) totalLines.push(`REG ${total.regFlat > 0 ? "+" : ""}${total.regFlat} (jet)`);
|
if (total.regFlat) totalLines.push(`REG ${total.regFlat > 0 ? "+" : ""}${total.regFlat}`);
|
||||||
for (const [key, label] of Object.entries(EFFECT_MOD_LABELS)) {
|
for (const [key, label] of Object.entries(EFFECT_MOD_LABELS)) {
|
||||||
const v = total[key];
|
const v = total[key];
|
||||||
if (typeof v !== "number" || !v) continue;
|
if (typeof v !== "number" || !v) continue;
|
||||||
@@ -579,7 +586,7 @@ function renderEffectsPanel(troll) {
|
|||||||
|
|
||||||
let html = "";
|
let html = "";
|
||||||
if (totalLines.length) {
|
if (totalLines.length) {
|
||||||
html += `<div class="fx-total"><div class="fx-total-title">Total des modificateurs (jets inclus)</div>`;
|
html += `<div class="fx-total"><div class="fx-total-title">Total des modificateurs</div>`;
|
||||||
html += totalLines.map(m => `<span class="fx-mod">${m}</span>`).join("");
|
html += totalLines.map(m => `<span class="fx-mod">${m}</span>`).join("");
|
||||||
html += "</div>";
|
html += "</div>";
|
||||||
}
|
}
|
||||||
@@ -606,6 +613,6 @@ if (typeof module !== "undefined" && module.exports) {
|
|||||||
POTION_IDS, POTION_DEFS, sumPotionMods, effTroll, formatPotionItem,
|
POTION_IDS, POTION_DEFS, sumPotionMods, effTroll, formatPotionItem,
|
||||||
makeRandomPotion, makePotionItem, drinkPotion, tickPotionTurns,
|
makeRandomPotion, makePotionItem, drinkPotion, tickPotionTurns,
|
||||||
describeActiveEffects, renderEffectsPanel, countActiveEffects, formatEffectMods,
|
describeActiveEffects, renderEffectsPanel, countActiveEffects, formatEffectMods,
|
||||||
rollMod, fmtStatLine, talentPctWithPotions, corruptionYZ,
|
sharedMod, fmtStatLine, talentPctWithPotions, corruptionYZ,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -174,9 +174,17 @@ assert.strictEqual(p.corruptionYZ(3).y, 0);
|
|||||||
assert.strictEqual(p.effTroll(t2).att, 3);
|
assert.strictEqual(p.effTroll(t2).att, 3);
|
||||||
const t3 = { att: 3, esq: 3, deg: 3, reg: 1, vue: 3, armor: 0, armorDice: 0, degBonus: 0, pvMax: 30, pv: 20, potionEffects: [], blockCamoTurns: 0, tour: 1 };
|
const t3 = { att: 3, esq: 3, deg: 3, reg: 1, vue: 3, armor: 0, armorDice: 0, degBonus: 0, pvMax: 30, pv: 20, potionEffects: [], blockCamoTurns: 0, tour: 1 };
|
||||||
p.drinkPotion(t3, p.makePotionItem("sangToh", 2), fixedRoll, () => {});
|
p.drinkPotion(t3, p.makePotionItem("sangToh", 2), fixedRoll, () => {});
|
||||||
assert.strictEqual(p.effTroll(t3).attFlat, 12, "2D6 fixé → +12 sur le jet d'attaque");
|
assert.strictEqual(p.effTroll(t3).attFlat, 12, "2D3 fixé → +12 sur le jet d'attaque");
|
||||||
assert.strictEqual(p.effTroll(t3).esqFlat, 12);
|
assert.strictEqual(p.effTroll(t3).esqFlat, 12);
|
||||||
assert.strictEqual(p.effTroll(t3).att, 3);
|
assert.strictEqual(p.effTroll(t3).att, 3);
|
||||||
|
// Le jet de la potion est unique : même valeur sur ATT et ESQ, bornée par XD3
|
||||||
|
for (let i = 0; i < 50; i++) {
|
||||||
|
const t4 = { att: 3, esq: 3, deg: 3, reg: 1, vue: 3, armor: 0, armorDice: 0, degBonus: 0, pvMax: 30, pv: 20, potionEffects: [], blockCamoTurns: 0, tour: 1 };
|
||||||
|
p.drinkPotion(t4, p.makePotionItem("sangToh", 4), g.rollDice, () => {});
|
||||||
|
const e4 = p.effTroll(t4);
|
||||||
|
assert.strictEqual(e4.attFlat, e4.esqFlat, "Sang de Toh Réroh : un seul jet pour ATT et ESQ");
|
||||||
|
assert(e4.attFlat >= 4 && e4.attFlat <= 12, "4D3 borné [4,12] : " + e4.attFlat);
|
||||||
|
}
|
||||||
p.tickPotionTurns(troll, () => {});
|
p.tickPotionTurns(troll, () => {});
|
||||||
assert.strictEqual(troll.tour, 2);
|
assert.strictEqual(troll.tour, 2);
|
||||||
troll.potionEffects[0].turnsLeft = 0;
|
troll.potionEffects[0].turnsLeft = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user