Files
mgt2-compendium-amiral-denisov/scripts/npcRollTableSync.js

148 lines
4.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 na pas pu être mis à jour.');
}
}