diff --git a/README.md b/README.md index 9ab8202..6c16e9a 100644 --- a/README.md +++ b/README.md @@ -152,9 +152,12 @@ non affilié au jeu original de Mountyhall SARL. ## Versions +- **1.7.1** (2026-06-12) — Les bonus ATT/ESQ/DEG/REG de l'équipement sont des bonus + **fixes** ajoutés aux jets, jamais des dés supplémentaires (un Gourdin donne + DEG +5 sur le jet, pas +5D3). - **1.7.0** (2026-06-11) — Équipement Mountypedia complet : 6 emplacements (Arme, Armure, Casque, Bouclier, Talisman, Bottes) et 55 objets dropables aux valeurs - de base officielles (ATT/ESQ/DEG/REG en dés, Armure/VUE/PV fixes, RM/MM en %). + de base officielles (bonus fixes, RM/MM en %). Armes à 2 mains incompatibles avec un bouclier, PV max d'équipement, tiers de drop par profondeur, pinceaux d'éditeur par emplacement, rétrocompatibilité des anciens niveaux publiés (specs weapon/armor mappées). Section « Équipement » diff --git a/js/game.js b/js/game.js index f4c9621..2e3db21 100644 --- a/js/game.js +++ b/js/game.js @@ -4,7 +4,7 @@ "use strict"; -const APP_VERSION = "1.7.0"; +const APP_VERSION = "1.7.1"; /* Alpha : maîtrise initiale haute pour les tests. Remettre 15 % / 15 % à la v1.0 officielle. */ const START_COMP_PCT = 90; diff --git a/js/gear.js b/js/gear.js index 6ad5d56..17eb22e 100644 --- a/js/gear.js +++ b/js/gear.js @@ -1,7 +1,8 @@ /* Équipement MountyHall — 6 emplacements, objets dropables actuels de la Mountypedia : * https://mountypedia.mountyhall.com/Mountyhall/{Arme,Armure,Casque,Bouclier,Talisman,Bottes} - * Valeurs de base (sans templates) : ATT/ESQ/DEG/REG modifient le nombre de dés, - * ARM/VUE/PV sont fixes, RM/MM en %. `tier` (1-5) borne la profondeur de drop. + * Valeurs de base (sans templates) : TOUS les bonus sont fixes — ATT/ESQ/DEG/REG + * s'ajoutent aux jets (jamais en dés), ARM/VUE/PV sont fixes, RM/MM en %. + * `tier` (1-5) borne la profondeur de drop. * Les armes à deux mains (twoHanded) sont incompatibles avec un bouclier. */ "use strict"; @@ -90,8 +91,8 @@ const LEGACY_WEAPON_NAMES = ["Épée Courte", "Gourdin", "Épée Longue", "Lame const LEGACY_ARMOR_NAMES = ["Armure de cuir", "Haubert de mailles", "Armure de plates"]; const GEAR_MOD_LABELS = [ - ["att", "ATT", " dé(s)"], ["esq", "ESQ", " dé(s)"], ["deg", "DEG", " dé(s)"], - ["reg", "REG", " dé(s)"], ["arm", "Armure", ""], ["vue", "VUE", ""], ["pv", "PV", ""], + ["att", "ATT", ""], ["esq", "ESQ", ""], ["deg", "DEG", ""], + ["reg", "REG", ""], ["arm", "Armure", ""], ["vue", "VUE", ""], ["pv", "PV", ""], ["rmPct", "RM", " %"], ["mmPct", "MM", " %"], ]; diff --git a/js/potions.js b/js/potions.js index b2f5bae..51c2e4d 100644 --- a/js/potions.js +++ b/js/potions.js @@ -414,19 +414,21 @@ function fmtStatLine(base, eff, faces, flat = 0, extra = 0) { } /* Caractéristiques effectives : base + effets magiques (potions, parchemins) - * + équipement (troll.gearMods, recalculé par game.js à chaque équipement). */ + * + équipement (troll.gearMods, recalculé par game.js à chaque équipement). + * Les bonus ATT/ESQ/DEG/REG de l'équipement sont des bonus FIXES sur les jets, + * jamais des dés supplémentaires. */ function effTroll(troll) { const m = sumPotionMods(troll.potionEffects); const g = troll.gearMods || {}; return { - att: Math.max(1, troll.att + m.att + (g.att || 0)), - attFlat: m.attFlat, - esq: Math.max(1, troll.esq + m.esq + (g.esq || 0)), - esqFlat: m.esqFlat, - deg: Math.max(1, troll.deg + m.deg + (g.deg || 0)), - degFlat: m.degFlat, - reg: Math.max(1, troll.reg + m.reg + (g.reg || 0)), - regFlat: m.regFlat, + att: Math.max(1, troll.att + m.att), + attFlat: m.attFlat + (g.att || 0), + esq: Math.max(1, troll.esq + m.esq), + esqFlat: m.esqFlat + (g.esq || 0), + deg: Math.max(1, troll.deg + m.deg), + degFlat: m.degFlat + (g.deg || 0), + reg: Math.max(1, troll.reg + m.reg), + regFlat: m.regFlat + (g.reg || 0), vue: Math.max(1, troll.vue + m.vue + (g.vue || 0)), armor: Math.max(0, troll.armor + m.armor + (g.arm || 0)), armorDice: troll.armorDice, diff --git a/js/treasures.js b/js/treasures.js index 0ce638b..fd3c276 100644 --- a/js/treasures.js +++ b/js/treasures.js @@ -83,7 +83,8 @@ function treasuresRender() { const gearCount = Object.values(GEAR).reduce((n, list) => n + list.length, 0); html += `

⚔️ Équipement (${gearCount})

Six emplacements : ${Object.values(GEAR_SLOTS).map(s => s.label).join(", ")}. - Les bonus ATT/ESQ/DEG/REG s'ajoutent en dés, Armure/VUE/PV sont fixes, RM/MM en %. + Tous les bonus d'équipement sont fixes : ATT/ESQ/DEG/REG s'ajoutent aux jets + (jamais en dés), Armure/VUE/PV aussi, RM/MM en %. Une arme à 2 mains est incompatible avec un bouclier. S'équiper coûte 2 PA. Valeurs de base de la Mountypedia (sans templates) ; les objets puissants ne se trouvent qu'en profondeur.

`; diff --git a/test/smoke.js b/test/smoke.js index 692428f..66a92bb 100644 --- a/test/smoke.js +++ b/test/smoke.js @@ -271,12 +271,15 @@ assert.strictEqual(g.itemFromSpec({ x: 1, y: 1, kind: "armor", idx: 0 }).name, " const t = { 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, bag: [], equip: { arme: null, armure: null, casque: null, bouclier: null, talisman: null, bottes: null }, gearMods: null }; - g.equipGear(t, gear.gearItemByName("arme", "Gourdin")); // att +2, esq −2, deg +5 + g.equipGear(t, gear.gearItemByName("arme", "Gourdin")); // att +2, esq −2, deg +5 (fixes) g.equipGear(t, gear.gearItemByName("armure", "Armure de cuir")); // esq +3, arm +4, rm +40 % let e = p.effTroll(t); - assert.strictEqual(e.att, 5, "Gourdin : ATT 3 + 2 dés"); - assert.strictEqual(e.deg, 8, "Gourdin : DEG 3 + 5 dés"); - assert.strictEqual(e.esq, 4, "ESQ 3 − 2 + 3"); + assert.strictEqual(e.att, 3, "l'équipement n'ajoute jamais de dés"); + assert.strictEqual(e.attFlat, 2, "Gourdin : ATT +2 fixe sur le jet"); + assert.strictEqual(e.deg, 3, "DEG reste 3D3"); + assert.strictEqual(e.degFlat, 5, "Gourdin : DEG +5 fixe"); + assert.strictEqual(e.esq, 3, "ESQ reste 3D6"); + assert.strictEqual(e.esqFlat, 1, "ESQ −2 (Gourdin) +3 (Armure de cuir) = +1 fixe"); assert.strictEqual(e.armor, 4, "Armure de cuir : armure +4"); assert.strictEqual(e.rmPct, 40, "Armure de cuir : RM +40 %"); // PV max d'équipement @@ -289,8 +292,8 @@ assert.strictEqual(g.itemFromSpec({ x: 1, y: 1, kind: "armor", idx: 0 }).name, " assert.strictEqual(t.pvMax, 30, "PV max retombé après déséquipement de la Rondache"); assert(t.bag.some(i => i.name === "Gourdin"), "l'ancienne arme est dans le sac"); e = p.effTroll(t); - assert.strictEqual(e.att, 1, "Hallebarde : ATT 3 − 5 → min 1"); - assert.strictEqual(e.deg, 15, "Hallebarde : DEG 3 + 12"); + assert.strictEqual(e.attFlat, -5, "Hallebarde : ATT −5 fixe"); + assert.strictEqual(e.degFlat, 12, "Hallebarde : DEG +12 fixe"); // rééquiper un bouclier range l'arme à 2 mains g.equipGear(t, gear.gearItemByName("bouclier", "Targe")); assert.strictEqual(t.equip.arme, null, "Targe : la Hallebarde est rangée");