v2.7.0 : templates de drop (table BDD, proba admin, application au drop)

- db.js : table templates + seed des 19 templates du CSV (mappes vers les
  mods + nouveau champ tour), templatesAll/setTemplate/resetCategory.
- server.js : /api/reference/templates.
- mp.js : config templateChance (0-100, bornee) ; applyGearTemplates applique
  jusqu'a 3 templates (6 si 2 mains), distincts, proba par emplacement,
  fusionne les mods (dont tour) et compose le nom ; applique au spawnItem.
  Solo vanilla.
- gear.js : GEAR_MOD_LABELS += tour (affichage 'TOUR +X mn').
- admin.html : champ Proba de template / emplacement.
- test/mp.js : test des templates (nb selon mains, distincts, proba 0).

Note : effet gameplay de tour (DLA) non cable, en attente de la regle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
perco
2026-06-14 00:17:53 +02:00
co-authored by Claude Opus 4.8
parent b55a6f8ac9
commit 00a4669928
8 changed files with 116 additions and 8 deletions
+55 -4
View File
@@ -23,6 +23,33 @@ const gearLib = require("./js/gear.js");
const MONSTER_KEYS = ["level", "att", "attMag", "esq", "deg", "degMag", "pv", "armor", "armorMag", "vue"];
const GEAR_KEYS = ["att", "attMag", "esq", "deg", "degMag", "reg", "arm", "armMag", "vue", "pv", "rmPct", "mmPct"];
/* Templates de drop façon MountyHall : des suffixes (« de l'Aigle », « des
* Mages »…) ajoutés aléatoirement à l'équipement qui tombe, selon une proba
* réglable côté admin. Leurs bonus s'ajoutent aux mods de l'objet ; `tour` est
* un modificateur de TOUR (DLA) propre aux templates. */
const TEMPLATE_KEYS = ["att", "attMag", "esq", "vue", "deg", "degMag", "arm", "armMag", "rmPct", "mmPct", "reg", "pv", "tour"];
const VANILLA_TEMPLATES = [
[1, "de l'Aigle", [0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
[2, "des Béhémoths", [0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 30]],
[3, "des Cyclopes", [0, 1, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0]],
[4, "des Enragés", [0, 1, -1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]],
[5, "de Feu", [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]],
[6, "des Mages", [0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0]],
[7, "de l'Orage", [0, 0, 2, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0]],
[8, "de l'Ours", [0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 5, 30]],
[9, "du Pic", [0, 0, -1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0]],
[10, "du Rat", [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
[11, "de Résistance", [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]],
[12, "de la Salamandre", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]],
[13, "du Temps", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -30]],
[14, "de la Terre", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 30]],
[15, "du Sable", [0, 0, 3, -1, 0, 0, 0, -1, 0, 0, 0, 0, 0]],
[16, "des Vampires", [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]],
[17, "des Duellistes", [0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
[18, "des Champions", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
[19, "des Anciens", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
];
/* Fourchettes de puissance « niveau X » vanilla (Mountypedia). La Longue-Vue
* vanilla tire dans {1,2,3,5,8} : tant que sa fourchette en base reste celle
* d'origine, on garde le tirage officiel. */
@@ -55,6 +82,12 @@ function vanillaGear() {
})));
}
function vanillaTemplates() {
return VANILLA_TEMPLATES.map(([id, name, vals]) => ({
id, name, ...Object.fromEntries(TEMPLATE_KEYS.map((k, i) => [k, vals[i]])),
}));
}
function vanillaTreasures(cat) {
const [ids, defs, ranges] = cat === "potions"
? [p.POTION_IDS, p.POTION_DEFS, POTION_POWER_DEFAULTS]
@@ -93,6 +126,9 @@ function init(file = ":memory:") {
id TEXT PRIMARY KEY, name TEXT, emoji TEXT,
powerMin INTEGER, powerMax INTEGER
);
CREATE TABLE IF NOT EXISTS templates (
id INTEGER PRIMARY KEY, name TEXT, ${TEMPLATE_KEYS.map(k => `${k} INTEGER`).join(", ")}
);
`);
const insM = DB.prepare(`INSERT OR IGNORE INTO monsters
(name, emoji, boss, isStatic, ${MONSTER_KEYS.join(", ")})
@@ -110,6 +146,9 @@ function init(file = ":memory:") {
const ins = DB.prepare(`INSERT OR IGNORE INTO ${cat} (id, name, emoji, powerMin, powerMax) VALUES (?, ?, ?, ?, ?)`);
for (const t of vanillaTreasures(cat)) ins.run(t.id, t.name, t.emoji, t.powerMin, t.powerMax);
}
const insT = DB.prepare(`INSERT OR IGNORE INTO templates (id, name, ${TEMPLATE_KEYS.join(", ")})
VALUES (?, ?, ${TEMPLATE_KEYS.map(() => "?").join(", ")})`);
for (const t of vanillaTemplates()) insT.run(t.id, t.name, ...TEMPLATE_KEYS.map(k => t[k]));
// Correctif des bases déjà créées : PufPuff avait été seedé à tort en [0,2]
// (le niveau 0 d'une potion n'existe pas, minimum 1) → on le ramène à [1,3].
// Le garde `powerMin = 0` évite d'écraser une plage éditée volontairement.
@@ -148,6 +187,10 @@ function treasuresAll(cat) {
return db().prepare(`SELECT * FROM ${cat === "scrolls" ? "scrolls" : "potions"}`).all();
}
function templatesAll() {
return db().prepare("SELECT * FROM templates ORDER BY id").all();
}
/* ---------- Écriture (page admin) ---------- */
function setMonster(name, vals) {
@@ -169,10 +212,18 @@ function setTreasureRange(cat, id, [min, max]) {
.run(min, max, id);
}
function setTemplate(id, vals) {
const keys = TEMPLATE_KEYS.filter(k => vals[k] != null);
if (!keys.length) return;
db().prepare(`UPDATE templates SET ${keys.map(k => `${k} = ?`).join(", ")} WHERE id = ?`)
.run(...keys.map(k => vals[k]), id);
}
/* Remet une catégorie entière aux valeurs vanilla. */
function resetCategory(cat) {
if (cat === "monsters") for (const m of vanillaMonsters()) setMonster(m.name, m);
if (cat === "gear") for (const it of vanillaGear()) setGear(it.slot, it.name, it);
if (cat === "templates") for (const t of vanillaTemplates()) setTemplate(t.id, t);
if (cat === "potions" || cat === "scrolls") {
for (const t of vanillaTreasures(cat)) setTreasureRange(cat, t.id, [t.powerMin, t.powerMax]);
}
@@ -180,8 +231,8 @@ function resetCategory(cat) {
module.exports = {
init, db,
MONSTER_KEYS, GEAR_KEYS, POTION_POWER_DEFAULTS, SCROLL_POWER_DEFAULTS,
vanillaMonsters, vanillaGear, vanillaTreasures,
monsters, gearAll, gearRow, treasureRange, treasuresAll,
setMonster, setGear, setTreasureRange, resetCategory,
MONSTER_KEYS, GEAR_KEYS, TEMPLATE_KEYS, POTION_POWER_DEFAULTS, SCROLL_POWER_DEFAULTS,
vanillaMonsters, vanillaGear, vanillaTreasures, vanillaTemplates,
monsters, gearAll, gearRow, treasureRange, treasuresAll, templatesAll,
setMonster, setGear, setTreasureRange, setTemplate, resetCategory,
};