import { NPC_ROLLTABLE_DEFINITIONS } from './data/npcTables.js'; const MODULE_ID = 'mgt2-compendium-amiral-denisov'; const PACK_ID = `${MODULE_ID}.tables-pnj`; const WORLD_FOLDER_NAME = 'MGT2 — Tables PNJ'; const ROLLTABLES_VERSION = 1; function entryText(entry) { if (typeof entry.d66 === 'number') return `[${entry.d66}] ${entry.text}`; if (typeof entry.roll === 'number') return `[${entry.roll}] ${entry.text}`; return entry.text; } function buildTableResults(entries) { return entries.map((entry, index) => ({ type: CONST.TABLE_RESULT_TYPES.TEXT, text: entryText(entry), weight: 1, range: [index + 1, index + 1], drawn: false, })); } function buildTableData(definition, extra = {}) { return { name: definition.name, description: 'Table synchronisée automatiquement depuis les règles PNJ du module.', formula: definition.formula, replacement: true, displayRoll: true, results: buildTableResults(definition.entries), flags: { [MODULE_ID]: { tableKey: definition.key, syncVersion: ROLLTABLES_VERSION, }, }, ...extra, }; } function normalizeResults(results) { return results.map((result) => ({ type: result.type, text: result.name ?? result.description ?? result.text ?? '', weight: result.weight, range: Array.from(result.range), })); } function needsSync(existing, wanted) { if (!existing) return true; if (existing.name !== wanted.name) return true; if (existing.formula !== wanted.formula) return true; if (existing.replacement !== wanted.replacement) return true; const currentVersion = existing.getFlag(MODULE_ID, 'syncVersion'); if (currentVersion !== ROLLTABLES_VERSION) return true; return JSON.stringify(normalizeResults(existing.results.contents)) !== JSON.stringify(normalizeResults(wanted.results)); } function getExistingKey(document) { return document.getFlag(MODULE_ID, 'tableKey') ?? document.name; } async function syncCompendiumPack() { const pack = game.packs.get(PACK_ID); if (!pack) throw new Error(`Pack introuvable : ${PACK_ID}`); await pack.getIndex(); const existingDocs = await pack.getDocuments(); const existingByKey = new Map(existingDocs.map((doc) => [getExistingKey(doc), doc])); const toCreate = []; const toUpdate = []; const wasLocked = pack.locked; try { if (wasLocked && typeof pack.configure === 'function') await pack.configure({ locked: false }); for (const definition of NPC_ROLLTABLE_DEFINITIONS) { const wanted = buildTableData(definition); const existing = existingByKey.get(definition.key); if (!existing) { toCreate.push(wanted); continue; } if (needsSync(existing, wanted)) { toUpdate.push({ _id: existing.id, ...wanted, }); } } if (toCreate.length) await RollTable.createDocuments(toCreate, { pack: pack.collection }); if (toUpdate.length) await RollTable.updateDocuments(toUpdate, { pack: pack.collection }); } finally { if (wasLocked && typeof pack.configure === 'function') await pack.configure({ locked: true }); } } async function getWorldFolder() { let folder = game.folders.find((entry) => entry.type === 'RollTable' && entry.name === WORLD_FOLDER_NAME); if (folder) return folder; return Folder.create({ name: WORLD_FOLDER_NAME, type: 'RollTable', color: '#c9a227', }); } async function syncWorldFallback() { const folder = await getWorldFolder(); const existingDocs = game.tables.filter((doc) => doc.folder?.id === folder.id); const existingByKey = new Map(existingDocs.map((doc) => [getExistingKey(doc), doc])); const toCreate = []; const toUpdate = []; for (const definition of NPC_ROLLTABLE_DEFINITIONS) { const wanted = buildTableData(definition, { folder: folder.id }); const existing = existingByKey.get(definition.key); if (!existing) { toCreate.push(wanted); continue; } if (needsSync(existing, wanted)) { toUpdate.push({ _id: existing.id, ...wanted, }); } } if (toCreate.length) await RollTable.createDocuments(toCreate); if (toUpdate.length) await RollTable.updateDocuments(toUpdate); } export async function syncNpcRollTables() { if (!game.user?.isGM) return; try { await syncCompendiumPack(); } catch (error) { console.error(`${MODULE_ID} | Échec de synchronisation du pack RollTable`, error); await syncWorldFallback(); ui.notifications.warn('Tables PNJ synchronisées dans le monde courant (fallback) — le pack de compendium n’a pas pu être mis à jour.'); } }