0.1.6 : debug potion
This commit is contained in:
@@ -169,6 +169,7 @@ header h1 { font-size: 1.3em; color: #8fbf5a; }
|
|||||||
|
|
||||||
#stats div { display: flex; justify-content: space-between; padding: 2px 0; }
|
#stats div { display: flex; justify-content: space-between; padding: 2px 0; }
|
||||||
#stats .stat-val { font-family: monospace; color: #f0e6c0; }
|
#stats .stat-val { font-family: monospace; color: #f0e6c0; }
|
||||||
|
#stats .stat-hint { color: #8a7a55; font-size: 0.82em; font-family: Georgia, serif; }
|
||||||
|
|
||||||
#effects-panel { margin-top: 4px; }
|
#effects-panel { margin-top: 4px; }
|
||||||
.fx-empty { color: #8a7a55; font-style: italic; font-size: 0.88em; line-height: 1.4; }
|
.fx-empty { color: #8a7a55; font-style: italic; font-size: 0.88em; line-height: 1.4; }
|
||||||
@@ -180,6 +181,7 @@ header h1 { font-size: 1.3em; color: #8fbf5a; }
|
|||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
.fx-total-title { color: #d8a040; font-size: 0.85em; margin-bottom: 6px; font-weight: bold; }
|
.fx-total-title { color: #d8a040; font-size: 0.85em; margin-bottom: 6px; font-weight: bold; }
|
||||||
|
.fx-total .fx-mod { margin: 0 6px 4px 0; }
|
||||||
.fx-card {
|
.fx-card {
|
||||||
background: #1f1810;
|
background: #1f1810;
|
||||||
border: 1px solid #4a3a20;
|
border: 1px solid #4a3a20;
|
||||||
|
|||||||
+5
-11
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const APP_VERSION = "0.1.5";
|
const APP_VERSION = "0.1.6";
|
||||||
|
|
||||||
/* 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;
|
||||||
@@ -1187,22 +1187,16 @@ function renderPanels() {
|
|||||||
$("troll-title").textContent = `${RACES[t.race].emoji} ${t.name}, ${t.race} niv. ${levelFromTotalPI(t.totalPI)}`;
|
$("troll-title").textContent = `${RACES[t.race].emoji} ${t.name}, ${t.race} niv. ${levelFromTotalPI(t.totalPI)}`;
|
||||||
|
|
||||||
const te = effTroll(t);
|
const te = effTroll(t);
|
||||||
const fmtDice = (n, faces, flat, extra = 0) => {
|
|
||||||
let s = `${n}D${faces}`;
|
|
||||||
const bonus = (flat || 0) + (extra || 0);
|
|
||||||
if (bonus) s += bonus > 0 ? ` +${bonus}` : ` ${bonus}`;
|
|
||||||
return s;
|
|
||||||
};
|
|
||||||
const pct = Math.max(0, t.pv / t.pvMax);
|
const pct = Math.max(0, t.pv / t.pvMax);
|
||||||
const hpClass = pct > 0.6 ? "high" : pct > 0.3 ? "mid" : "";
|
const hpClass = pct > 0.6 ? "high" : pct > 0.3 ? "mid" : "";
|
||||||
$("stats").innerHTML = `
|
$("stats").innerHTML = `
|
||||||
<div><span>Tour</span><span class="stat-val">${t.tour}</span></div>
|
<div><span>Tour</span><span class="stat-val">${t.tour}</span></div>
|
||||||
<div><span>PV</span><span class="stat-val">${t.pv} / ${t.pvMax}</span></div>
|
<div><span>PV</span><span class="stat-val">${t.pv} / ${t.pvMax}</span></div>
|
||||||
<div class="hp-bar-wrap"><div class="hp-bar ${hpClass}" style="width:${pct * 100}%"></div></div>
|
<div class="hp-bar-wrap"><div class="hp-bar ${hpClass}" style="width:${pct * 100}%"></div></div>
|
||||||
<div><span>Attaque</span><span class="stat-val">${fmtDice(te.att, 6, te.attFlat)}</span></div>
|
<div><span>Attaque</span><span class="stat-val">${fmtStatLine(t.att, te.att, 6, te.attFlat)}</span></div>
|
||||||
<div><span>Esquive</span><span class="stat-val">${fmtDice(te.esq, 6, te.esqFlat)}</span></div>
|
<div><span>Esquive</span><span class="stat-val">${fmtStatLine(t.esq, te.esq, 6, te.esqFlat)}</span></div>
|
||||||
<div><span>Dégâts</span><span class="stat-val">${fmtDice(te.deg, 3, te.degFlat, te.degBonus)}</span></div>
|
<div><span>Dégâts</span><span class="stat-val">${fmtStatLine(t.deg, te.deg, 3, te.degFlat, te.degBonus)}</span></div>
|
||||||
<div><span>Régénération</span><span class="stat-val">${fmtDice(te.reg, 3, te.regFlat)}</span></div>
|
<div><span>Régénération</span><span class="stat-val">${fmtStatLine(t.reg, te.reg, 3, te.regFlat)}</span></div>
|
||||||
<div><span>Armure</span><span class="stat-val">${te.armor}${t.armorDice ? "+" + t.armorDice + "D3" : ""}</span></div>
|
<div><span>Armure</span><span class="stat-val">${te.armor}${t.armorDice ? "+" + t.armorDice + "D3" : ""}</span></div>
|
||||||
<div><span>Vue</span><span class="stat-val">${te.vue}</span></div>
|
<div><span>Vue</span><span class="stat-val">${te.vue}</span></div>
|
||||||
<div><span>${RACES[t.race].comp.name}</span><span class="stat-val">${t.comp.pct} %</span></div>
|
<div><span>${RACES[t.race].comp.name}</span><span class="stat-val">${t.comp.pct} %</span></div>
|
||||||
|
|||||||
+37
-22
@@ -72,9 +72,10 @@ const POTION_DEFS = {
|
|||||||
duration: 5,
|
duration: 5,
|
||||||
rollPower: () => potRand(3, 7),
|
rollPower: () => potRand(3, 7),
|
||||||
build(_t, p) {
|
build(_t, p) {
|
||||||
|
const lines = [`DEG +${p} dés`, `REG +${p} dés`];
|
||||||
return {
|
return {
|
||||||
log: `Elixir de Bonne Bouffe : DEG +${p}, REG +${p} pendant 5 tours.`,
|
log: `Elixir de Bonne Bouffe : ${lines.join(", ")} pendant 5 tours.`,
|
||||||
effects: [makeEffect("Elixir de Bonne Bouffe", "🍖", 5, { deg: p, reg: p })],
|
effects: [makeEffect("Elixir de Bonne Bouffe", "🍖", 5, { deg: p, reg: p }, lines)],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -153,9 +154,10 @@ const POTION_DEFS = {
|
|||||||
build(troll, p, rollDice) {
|
build(troll, p, rollDice) {
|
||||||
const heal = rollDice(2, 3).total;
|
const heal = rollDice(2, 3).total;
|
||||||
troll.pv = Math.min(troll.pvMax, troll.pv + heal);
|
troll.pv = Math.min(troll.pvMax, troll.pv + heal);
|
||||||
|
const lines = [`DEG +${p} dés`, `REG +${p} dés`, `PV +${heal} (2D3)`];
|
||||||
return {
|
return {
|
||||||
log: `Extrait de DjhinTonik : DEG +${p}, REG +${p}, +${heal} PV (2D3) pendant 4 tours.`,
|
log: `Extrait de DjhinTonik : ${lines.join(", ")} pendant 4 tours.`,
|
||||||
effects: [makeEffect("Extrait de DjhinTonik", "🧞", 4, { deg: p, reg: p })],
|
effects: [makeEffect("Extrait de DjhinTonik", "🧞", 4, { deg: p, reg: p }, lines)],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -383,13 +385,27 @@ function sumPotionMods(effects) {
|
|||||||
mmPct: 0, rmPct: 0, concentrationPct: 0, dlaBonusPA: 0,
|
mmPct: 0, rmPct: 0, concentrationPct: 0, dlaBonusPA: 0,
|
||||||
};
|
};
|
||||||
for (const e of effects || []) {
|
for (const e of effects || []) {
|
||||||
|
if (e.blockCamo) continue;
|
||||||
for (const k of Object.keys(m)) {
|
for (const k of Object.keys(m)) {
|
||||||
if (e[k]) m[k] += e[k];
|
if (typeof e[k] === "number") m[k] += e[k];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Affichage caractéristique : valeur effective + rappel de la base si modifiée. */
|
||||||
|
function fmtStatLine(base, eff, faces, flat = 0, extra = 0) {
|
||||||
|
const diceDelta = eff - base;
|
||||||
|
const jetBonus = (flat || 0) + (extra || 0);
|
||||||
|
let main = `${eff}D${faces}`;
|
||||||
|
if (jetBonus) main += jetBonus > 0 ? ` +${jetBonus}` : ` ${jetBonus}`;
|
||||||
|
if (diceDelta !== 0) {
|
||||||
|
const sign = diceDelta > 0 ? "+" : "";
|
||||||
|
return `${main} <small class="stat-hint">(${base}D${faces} ${sign}${diceDelta})</small>`;
|
||||||
|
}
|
||||||
|
return main;
|
||||||
|
}
|
||||||
|
|
||||||
function effTroll(troll) {
|
function effTroll(troll) {
|
||||||
const m = sumPotionMods(troll.potionEffects);
|
const m = sumPotionMods(troll.potionEffects);
|
||||||
return {
|
return {
|
||||||
@@ -477,21 +493,20 @@ function tickPotionTurns(troll, logFn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const EFFECT_MOD_LABELS = {
|
const EFFECT_MOD_LABELS = {
|
||||||
att: ["ATT", "dés"], esq: ["ESQ", "dés"], deg: ["DEG", "dés"], reg: ["REG", "dés"],
|
att: "ATT", esq: "ESQ", deg: "DEG", reg: "REG", vue: "VUE", armor: "Armure",
|
||||||
vue: ["VUE", ""], armor: ["Armure", ""],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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}`);
|
if (effect.attFlat) parts.push(`ATT ${effect.attFlat > 0 ? "+" : ""}${effect.attFlat} (jet)`);
|
||||||
if (effect.esqFlat) parts.push(`ESQ ${effect.esqFlat > 0 ? "+" : ""}${effect.esqFlat}`);
|
if (effect.esqFlat) parts.push(`ESQ ${effect.esqFlat > 0 ? "+" : ""}${effect.esqFlat} (jet)`);
|
||||||
if (effect.degFlat) parts.push(`DEG ${effect.degFlat > 0 ? "+" : ""}${effect.degFlat}`);
|
if (effect.degFlat) parts.push(`DEG ${effect.degFlat > 0 ? "+" : ""}${effect.degFlat} (jet)`);
|
||||||
if (effect.regFlat) parts.push(`REG ${effect.regFlat > 0 ? "+" : ""}${effect.regFlat}`);
|
if (effect.regFlat) parts.push(`REG ${effect.regFlat > 0 ? "+" : ""}${effect.regFlat} (jet)`);
|
||||||
for (const [key, [label, suffix]] 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 (!v) continue;
|
if (typeof v !== "number" || !v) continue;
|
||||||
parts.push(`${label} ${v > 0 ? "+" : ""}${v}${suffix ? " " + suffix : ""}`);
|
parts.push(`${label} ${v > 0 ? "+" : ""}${v}${["att", "esq", "deg", "reg"].includes(key) ? " dés" : ""}`);
|
||||||
}
|
}
|
||||||
if (effect.mmPct) parts.push(`MM ${effect.mmPct > 0 ? "+" : ""}${effect.mmPct} %`);
|
if (effect.mmPct) parts.push(`MM ${effect.mmPct > 0 ? "+" : ""}${effect.mmPct} %`);
|
||||||
if (effect.rmPct) parts.push(`RM ${effect.rmPct > 0 ? "+" : ""}${effect.rmPct} %`);
|
if (effect.rmPct) parts.push(`RM ${effect.rmPct > 0 ? "+" : ""}${effect.rmPct} %`);
|
||||||
@@ -547,14 +562,14 @@ 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}`);
|
if (total.attFlat) totalLines.push(`ATT ${total.attFlat > 0 ? "+" : ""}${total.attFlat} (jet)`);
|
||||||
if (total.esqFlat) totalLines.push(`ESQ ${total.esqFlat > 0 ? "+" : ""}${total.esqFlat}`);
|
if (total.esqFlat) totalLines.push(`ESQ ${total.esqFlat > 0 ? "+" : ""}${total.esqFlat} (jet)`);
|
||||||
if (total.degFlat) totalLines.push(`DEG ${total.degFlat > 0 ? "+" : ""}${total.degFlat}`);
|
if (total.degFlat) totalLines.push(`DEG ${total.degFlat > 0 ? "+" : ""}${total.degFlat} (jet)`);
|
||||||
if (total.regFlat) totalLines.push(`REG ${total.regFlat > 0 ? "+" : ""}${total.regFlat}`);
|
if (total.regFlat) totalLines.push(`REG ${total.regFlat > 0 ? "+" : ""}${total.regFlat} (jet)`);
|
||||||
for (const [key, [label, suffix]] 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 (!v) continue;
|
if (typeof v !== "number" || !v) continue;
|
||||||
totalLines.push(`${label} ${v > 0 ? "+" : ""}${v}${suffix ? " " + suffix : ""}`);
|
totalLines.push(`${label} ${v > 0 ? "+" : ""}${v}${["att", "esq", "deg", "reg"].includes(key) ? " dés" : ""}`);
|
||||||
}
|
}
|
||||||
if (total.mmPct) totalLines.push(`MM ${total.mmPct > 0 ? "+" : ""}${total.mmPct} %`);
|
if (total.mmPct) totalLines.push(`MM ${total.mmPct > 0 ? "+" : ""}${total.mmPct} %`);
|
||||||
if (total.rmPct) totalLines.push(`RM ${total.rmPct > 0 ? "+" : ""}${total.rmPct} %`);
|
if (total.rmPct) totalLines.push(`RM ${total.rmPct > 0 ? "+" : ""}${total.rmPct} %`);
|
||||||
@@ -591,6 +606,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, talentPctWithPotions, corruptionYZ,
|
rollMod, fmtStatLine, talentPctWithPotions, corruptionYZ,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -185,6 +185,13 @@ assert.strictEqual(p.corruptionYZ(3).y, 0);
|
|||||||
assert.strictEqual(p.effTroll(troll).deg, 3);
|
assert.strictEqual(p.effTroll(troll).deg, 3);
|
||||||
assert.strictEqual(p.effTroll(troll).attFlat, 0);
|
assert.strictEqual(p.effTroll(troll).attFlat, 0);
|
||||||
}
|
}
|
||||||
|
// DjhinTonik : +X dés de DEG et REG (pas un jet D3)
|
||||||
|
{
|
||||||
|
const t = { att: 3, esq: 3, deg: 4, reg: 1, vue: 3, armor: 0, armorDice: 0, degBonus: 0, pvMax: 30, pv: 20, potionEffects: [], blockCamoTurns: 0, tour: 1 };
|
||||||
|
p.drinkPotion(t, p.makePotionItem("djhinTonik", 5), g.rollDice, () => {});
|
||||||
|
assert.strictEqual(p.effTroll(t).deg, 9, "DEG 4 + 5 dés potion = 9D3");
|
||||||
|
assert.strictEqual(p.effTroll(t).reg, 6, "REG 1 + 5 dés potion = 6D3");
|
||||||
|
}
|
||||||
// Jet d'attaque : bonus potion ajouté au total des D6
|
// Jet d'attaque : bonus potion ajouté au total des D6
|
||||||
{
|
{
|
||||||
const r = g.resolveAttack({ att: 3, attFlat: 12, deg: 2, degBonus: 0 }, { esq: 1 });
|
const r = g.resolveAttack({ att: 3, attFlat: 12, deg: 2, degBonus: 0 }, { esq: 1 });
|
||||||
|
|||||||
Reference in New Issue
Block a user