1.7.1 : bonus d'équipement fixes sur les jets, jamais en dés

ATT/ESQ/DEG/REG d'équipement alimentent attFlat/esqFlat/degFlat/regFlat
dans effTroll (Gourdin = DEG +5 sur le jet, pas +5D3).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
perco
2026-06-12 00:02:27 +02:00
co-authored by Claude Fable 5
parent 2f21f867a5
commit 61a8cee0fc
6 changed files with 32 additions and 22 deletions
+4 -1
View File
@@ -152,9 +152,12 @@ non affilié au jeu original de Mountyhall SARL.
## Versions ## 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, - **1.7.0** (2026-06-11) — Équipement Mountypedia complet : 6 emplacements (Arme,
Armure, Casque, Bouclier, Talisman, Bottes) et 55 objets dropables aux valeurs 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 Armes à 2 mains incompatibles avec un bouclier, PV max d'équipement, tiers de
drop par profondeur, pinceaux d'éditeur par emplacement, rétrocompatibilité des drop par profondeur, pinceaux d'éditeur par emplacement, rétrocompatibilité des
anciens niveaux publiés (specs weapon/armor mappées). Section « Équipement » anciens niveaux publiés (specs weapon/armor mappées). Section « Équipement »
+1 -1
View File
@@ -4,7 +4,7 @@
"use strict"; "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. */ /* 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;
+5 -4
View File
@@ -1,7 +1,8 @@
/* Équipement MountyHall — 6 emplacements, objets dropables actuels de la Mountypedia : /* Équipement MountyHall — 6 emplacements, objets dropables actuels de la Mountypedia :
* https://mountypedia.mountyhall.com/Mountyhall/{Arme,Armure,Casque,Bouclier,Talisman,Bottes} * 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, * Valeurs de base (sans templates) : TOUS les bonus sont fixes — ATT/ESQ/DEG/REG
* ARM/VUE/PV sont fixes, RM/MM en %. `tier` (1-5) borne la profondeur de drop. * 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. */ * Les armes à deux mains (twoHanded) sont incompatibles avec un bouclier. */
"use strict"; "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 LEGACY_ARMOR_NAMES = ["Armure de cuir", "Haubert de mailles", "Armure de plates"];
const GEAR_MOD_LABELS = [ const GEAR_MOD_LABELS = [
["att", "ATT", " dé(s)"], ["esq", "ESQ", " dé(s)"], ["deg", "DEG", " dé(s)"], ["att", "ATT", ""], ["esq", "ESQ", ""], ["deg", "DEG", ""],
["reg", "REG", " dé(s)"], ["arm", "Armure", ""], ["vue", "VUE", ""], ["pv", "PV", ""], ["reg", "REG", ""], ["arm", "Armure", ""], ["vue", "VUE", ""], ["pv", "PV", ""],
["rmPct", "RM", " %"], ["mmPct", "MM", " %"], ["rmPct", "RM", " %"], ["mmPct", "MM", " %"],
]; ];
+11 -9
View File
@@ -414,19 +414,21 @@ function fmtStatLine(base, eff, faces, flat = 0, extra = 0) {
} }
/* Caractéristiques effectives : base + effets magiques (potions, parchemins) /* 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) { function effTroll(troll) {
const m = sumPotionMods(troll.potionEffects); const m = sumPotionMods(troll.potionEffects);
const g = troll.gearMods || {}; const g = troll.gearMods || {};
return { return {
att: Math.max(1, troll.att + m.att + (g.att || 0)), att: Math.max(1, troll.att + m.att),
attFlat: m.attFlat, attFlat: m.attFlat + (g.att || 0),
esq: Math.max(1, troll.esq + m.esq + (g.esq || 0)), esq: Math.max(1, troll.esq + m.esq),
esqFlat: m.esqFlat, esqFlat: m.esqFlat + (g.esq || 0),
deg: Math.max(1, troll.deg + m.deg + (g.deg || 0)), deg: Math.max(1, troll.deg + m.deg),
degFlat: m.degFlat, degFlat: m.degFlat + (g.deg || 0),
reg: Math.max(1, troll.reg + m.reg + (g.reg || 0)), reg: Math.max(1, troll.reg + m.reg),
regFlat: m.regFlat, regFlat: m.regFlat + (g.reg || 0),
vue: Math.max(1, troll.vue + m.vue + (g.vue || 0)), vue: Math.max(1, troll.vue + m.vue + (g.vue || 0)),
armor: Math.max(0, troll.armor + m.armor + (g.arm || 0)), armor: Math.max(0, troll.armor + m.armor + (g.arm || 0)),
armorDice: troll.armorDice, armorDice: troll.armorDice,
+2 -1
View File
@@ -83,7 +83,8 @@ function treasuresRender() {
const gearCount = Object.values(GEAR).reduce((n, list) => n + list.length, 0); const gearCount = Object.values(GEAR).reduce((n, list) => n + list.length, 0);
html += `<h2 class="tz-section">⚔️ Équipement (${gearCount})</h2> html += `<h2 class="tz-section">⚔️ Équipement (${gearCount})</h2>
<p class="tz-intro">Six emplacements : ${Object.values(GEAR_SLOTS).map(s => s.label).join(", ")}. <p class="tz-intro">Six emplacements : ${Object.values(GEAR_SLOTS).map(s => s.label).join(", ")}.
Les bonus ATT/ESQ/DEG/REG s'ajoutent en <b>dés</b>, Armure/VUE/PV sont fixes, RM/MM en %. Tous les bonus d'équipement sont <b>fixes</b> : ATT/ESQ/DEG/REG s'ajoutent aux jets
(jamais en dés), Armure/VUE/PV aussi, RM/MM en %.
Une arme <b>à 2 mains</b> est incompatible avec un bouclier. S'équiper coûte <b>2 PA</b>. Une arme <b>à 2 mains</b> est incompatible avec un bouclier. S'équiper coûte <b>2 PA</b>.
Valeurs de base de la Mountypedia (sans templates) ; les objets puissants ne se trouvent Valeurs de base de la Mountypedia (sans templates) ; les objets puissants ne se trouvent
qu'en profondeur.</p>`; qu'en profondeur.</p>`;
+9 -6
View File
@@ -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, 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: [], potionEffects: [], blockCamoTurns: 0, tour: 1, bag: [],
equip: { arme: null, armure: null, casque: null, bouclier: null, talisman: null, bottes: null }, gearMods: null }; 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 % g.equipGear(t, gear.gearItemByName("armure", "Armure de cuir")); // esq +3, arm +4, rm +40 %
let e = p.effTroll(t); let e = p.effTroll(t);
assert.strictEqual(e.att, 5, "Gourdin : ATT 3 + 2 dés"); assert.strictEqual(e.att, 3, "l'équipement n'ajoute jamais de dés");
assert.strictEqual(e.deg, 8, "Gourdin : DEG 3 + 5 dés"); assert.strictEqual(e.attFlat, 2, "Gourdin : ATT +2 fixe sur le jet");
assert.strictEqual(e.esq, 4, "ESQ 3 2 + 3"); 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.armor, 4, "Armure de cuir : armure +4");
assert.strictEqual(e.rmPct, 40, "Armure de cuir : RM +40 %"); assert.strictEqual(e.rmPct, 40, "Armure de cuir : RM +40 %");
// PV max d'équipement // 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.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"); assert(t.bag.some(i => i.name === "Gourdin"), "l'ancienne arme est dans le sac");
e = p.effTroll(t); e = p.effTroll(t);
assert.strictEqual(e.att, 1, "Hallebarde : ATT 3 5 → min 1"); assert.strictEqual(e.attFlat, -5, "Hallebarde : ATT 5 fixe");
assert.strictEqual(e.deg, 15, "Hallebarde : DEG 3 + 12"); assert.strictEqual(e.degFlat, 12, "Hallebarde : DEG +12 fixe");
// rééquiper un bouclier range l'arme à 2 mains // rééquiper un bouclier range l'arme à 2 mains
g.equipGear(t, gear.gearItemByName("bouclier", "Targe")); g.equipGear(t, gear.gearItemByName("bouclier", "Targe"));
assert.strictEqual(t.equip.arme, null, "Targe : la Hallebarde est rangée"); assert.strictEqual(t.equip.arme, null, "Targe : la Hallebarde est rangée");