diff --git a/README.md b/README.md index 9406330..e2b6e69 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ lance directement une partie (utilisé pour les captures d'écran et les tests). | Combat | Somme ATT D6 vs somme ESQ D6, dégâts DEG D3 − armure | Identique, avec le détail des jets dans le journal | | Talents | Compétence + sortilège réservés par race, 15 % de maîtrise initiale, jet D100 sous le %, progression à l'usage (+1D6 % < 50, +1D3 % < 75, +1 % ensuite), plafonds 90 %/80 %, échec = PA partiellement remboursés | Identique | | Magie | Seuil de Résistance basé sur MM vs RM, borné 10–90 % | Identique : jet de résistance des monstres → effets de moitié | -| Progression | PX → PI à l'entraînement, coût (dés + 1) × coût racial | Identique, avec réduction sur la caractéristique favorite de la race | +| Progression | PX → PI, le N-ième achat coûte N × coût de base racial (table de Rules_3.php) | Identique : 16 PI de base (12 pour la caractéristique favorite), REG 30 (Darkling 22), Armure naturelle 30 pour tous, PV par tranche de 10 | | Niveaux | 10 × N PI pour atteindre le niveau N | Identique | | Races | 5 races, chacune avec sort/compétence propre | Les 5 races avec leur capacité signature (voir ci-dessous) | | Coûts en PA | Déplacement 1–3, attaque, ramasser, équiper, potion… | Déplacement 1, attaque 3, ramasser 1, équiper 2, potion 1 | @@ -61,8 +61,22 @@ Profils de base repris des pages officielles, compétence (🥋 2 PA) et sortil | 🟡 Tomawak | ATT 3D6 · ESQ 3D6 · DEG 3D3 · REG 1D3 · PV 30 · Vue 4 | **Camouflage** : invisible, jet sous 75 % de la maîtrise à chaque pas | **Projectile Magique** : à distance (portée = Vue), bonus de proximité | | 🟣 Darkling | ATT 3D6 · ESQ 3D6 · DEG 3D3 · REG 2D3 · PV 30 · Vue 3 | **Balayage** : déstabilise (la cible perd son tour) | **Siphon des Âmes** : 1D3 par dé de REG, ignore toute armure, nécrose −ATT | -Le coût en PI reste réduit sur la caractéristique favorite de chaque race -(ATT Skrim, PV Durakuir, DEG Kastar, Vue Tomawak, REG Darkling). +### Coûts d'amélioration (officiels, [Rules_3.php](https://www.mountyhall.com/MH_Rules/Rules_3.php)) + +Le N-ième achat d'une caractéristique coûte N × le coût de base : + +| Amélioration | Skrim | Durakuir | Kastar | Tomawak | Darkling | +|---|---|---|---|---|---| +| +1D6 Attaque | **12** | 16 | 16 | 16 | 16 | +| +1D6 Esquive | 16 | 16 | 16 | 16 | 16 | +| +1D3 Dégâts | 16 | 16 | **12** | 16 | 16 | +| +1D3 Régénération | 30 | 30 | 30 | 30 | **22** | +| +1D3 Armure naturelle | 30 | 30 | 30 | 30 | 30 | +| +1 Vue | 16 | 16 | 16 | **12** | 16 | +| +10 PV | 16 | **12** | 16 | 16 | 16 | + +(L'amélioration « 30 minutes de DLA » du jeu original n'a pas d'équivalent ici, +la DLA étant instantanée.) ## Contrôles @@ -128,6 +142,9 @@ non affilié au jeu original de Mountyhall SARL. ## Versions +- **1.3.1** (2026-06-11) — Coûts d'amélioration officiels de Rules_3.php (N-ième + achat = N × base, favorisée 12 PI, REG 30/22, PV par 10) et armure naturelle + en D3 achetable (30 PI pour toutes les races). - **1.3.0** (2026-06-11) — Races fidèles aux règles officielles : profils de base exacts, dégâts en D3, compétence + sortilège réservés par race avec maîtrise en % progressant à l'usage, jets de résistance des monstres, statuts (à terre, hypnose, diff --git a/js/game.js b/js/game.js index 40bc825..a233bca 100644 --- a/js/game.js +++ b/js/game.js @@ -26,7 +26,9 @@ function resolveAttack(attacker, defender, opts = {}) { if (result.hit) { const deg = rollDice(attacker.deg, 3); result.rawDamage = deg.total + (attacker.degBonus || 0); - const armor = opts.ignoreArmor ? 0 : (defender.armor || 0); + // armure : réduction fixe (équipement) + armure naturelle en D3 (achetée en PI) + const armor = opts.ignoreArmor ? 0 + : (defender.armor || 0) + (defender.armorDice ? rollDice(defender.armorDice, 3).total : 0); result.damage = Math.max(1, result.rawDamage - armor); } return result; @@ -53,14 +55,17 @@ function resolveSpell(mm, rm) { return { sr, roll, success: roll <= sr }; } -/* Coût en PI du prochain dé d'une caractéristique : (dés actuels + 1) × coût de base, - * réduit pour la caractéristique favorite de la race (cf. règles MH). */ -function improveCost(stat, currentValue, race) { - const base = { att: 18, esq: 18, deg: 18, reg: 15, pv: 10, vue: 15 }; +/* Coûts d'amélioration officiels (MH_Rules/Rules_3.php) : le N-ième achat d'une + * caractéristique coûte N × coût de base de la race. La caractéristique favorite + * est à 12 PI (REG du Darkling : 22), le reste à 16, REG à 30, Armure à 30. + * `bought` = nombre d'améliorations déjà achetées dans cette caractéristique. */ +const IMPROVE_BASE = { att: 16, esq: 16, deg: 16, reg: 30, pv: 16, vue: 16, armor: 30 }; +const IMPROVE_FAVORED = { att: 12, deg: 12, pv: 12, vue: 12, reg: 22 }; + +function improveCost(stat, bought, race) { const favored = RACES[race].favored === stat; - const mult = favored ? Math.ceil(base[stat] * 2 / 3) : base[stat]; - if (stat === "pv") return mult; // +5 PV, coût fixe - return (currentValue + 1) * mult; + const base = favored ? IMPROVE_FAVORED[stat] : IMPROVE_BASE[stat]; + return (bought + 1) * base; } /* Niveau d'ancienneté : passer au niveau N coûte 10×N PI gagnés (cumulés). */ @@ -292,7 +297,8 @@ function newGame(name, race, customLevel = null) { name, race, att: s.att, esq: s.esq, deg: s.deg, reg: s.reg, pv: s.pvMax, pvMax: s.pvMax, vue: s.vue, - degBonus: 0, armor: 0, + degBonus: 0, armor: 0, armorDice: 0, + bought: { att: 0, esq: 0, deg: 0, reg: 0, pv: 0, vue: 0, armor: 0 }, comp: { pct: 15 }, sort: { pct: 15 }, fatigue: 0, compUsed: false, weapon: null, armorItem: null, pa: PA_PER_TURN, pi: 0, totalPI: 0, gold: 0, @@ -744,13 +750,14 @@ function descend() { function improveStat(stat) { const t = G.troll; - const current = stat === "pv" ? t.pvMax : t[stat]; - const cost = improveCost(stat, stat === "pv" ? 0 : current, t.race); + const cost = improveCost(stat, t.bought[stat], t.race); if (t.pi < cost) return; t.pi -= cost; - if (stat === "pv") { t.pvMax += 5; t.pv += 5; } + t.bought[stat] += 1; + if (stat === "pv") { t.pvMax += 10; t.pv += 10; } + else if (stat === "armor") t.armorDice += 1; else t[stat] += 1; - const label = { att: "Attaque", esq: "Esquive", deg: "Dégâts", reg: "Régénération", pv: "PV max", vue: "Vue" }[stat]; + const label = { att: "Attaque", esq: "Esquive", deg: "Dégâts", reg: "Régénération", pv: "PV max", vue: "Vue", armor: "Armure naturelle" }[stat]; log(`📈 Entraînement : ${label} améliorée pour ${cost} PI.`, "good"); if (stat === "vue") updateFov(); afterAction(); @@ -945,7 +952,7 @@ function renderPanels() {