Migration vers le système officiel
This commit is contained in:
@@ -0,0 +1,406 @@
|
||||
import { inferWeaponSkillFromName } from './mgt2eSkills.js';
|
||||
|
||||
const MODULE_ID = 'mgt2-compendium-amiral-denisov';
|
||||
const MIGRATION_SETTING = 'mgt2eMigrationVersion';
|
||||
const MIGRATION_VERSION = 2;
|
||||
|
||||
const ITEM_PACKS = [
|
||||
'armures',
|
||||
'competences',
|
||||
'maladie-poison-and-blessure',
|
||||
'objet',
|
||||
'equipement',
|
||||
'ordinateur',
|
||||
'contenant-sac-coffre',
|
||||
'espece',
|
||||
'armes',
|
||||
'talents-psioniques',
|
||||
'carrieres',
|
||||
];
|
||||
|
||||
Hooks.once('init', () => {
|
||||
game.settings.register(MODULE_ID, MIGRATION_SETTING, {
|
||||
scope: 'world',
|
||||
config: false,
|
||||
type: Number,
|
||||
default: 0,
|
||||
});
|
||||
});
|
||||
|
||||
Hooks.once('ready', async () => {
|
||||
if (game.system?.id !== 'mgt2e' || !game.user?.isGM) return;
|
||||
|
||||
const currentVersion = game.settings.get(MODULE_ID, MIGRATION_SETTING) ?? 0;
|
||||
if (currentVersion >= MIGRATION_VERSION) return;
|
||||
|
||||
ui.notifications.info('Migration mgt2e du module en cours...');
|
||||
|
||||
try {
|
||||
for (const packName of ITEM_PACKS) {
|
||||
await migrateItemPack(packName);
|
||||
}
|
||||
|
||||
await game.settings.set(MODULE_ID, MIGRATION_SETTING, MIGRATION_VERSION);
|
||||
ui.notifications.info('Migration mgt2e du module terminée.');
|
||||
} catch (error) {
|
||||
console.error(`${MODULE_ID} | Migration mgt2e impossible`, error);
|
||||
ui.notifications.error(`Migration mgt2e inachevee : ${error.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
async function migrateItemPack(packName) {
|
||||
const collection = `${MODULE_ID}.${packName}`;
|
||||
const pack = game.packs.get(collection);
|
||||
if (!pack || pack.documentName !== 'Item') return;
|
||||
|
||||
const originalLocked = pack.locked;
|
||||
if (originalLocked) {
|
||||
await pack.configure({ locked: false });
|
||||
}
|
||||
|
||||
try {
|
||||
const documents = await pack.getDocuments();
|
||||
const folderNames = buildFolderNameMap(pack);
|
||||
const failures = [];
|
||||
|
||||
for (const document of documents) {
|
||||
const folderId = document.folder?.id ?? document.folder ?? null;
|
||||
const update = buildMigratedItemData(document, packName, folderNames.get(folderId));
|
||||
if (!update) continue;
|
||||
|
||||
try {
|
||||
await document.update(update, { diff: false, recursive: false });
|
||||
} catch (error) {
|
||||
failures.push(`${document.name}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (failures.length) {
|
||||
throw new Error(`${packName} (${failures.length} erreurs) — ${failures.slice(0, 5).join(' | ')}`);
|
||||
}
|
||||
} finally {
|
||||
if (originalLocked) {
|
||||
await pack.configure({ locked: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildFolderNameMap(pack) {
|
||||
const folders = new Map();
|
||||
for (const folder of pack.folders ?? []) {
|
||||
folders.set(folder.id, folder.name ?? '');
|
||||
}
|
||||
return folders;
|
||||
}
|
||||
|
||||
function buildMigratedItemData(document, packName, folderName = '') {
|
||||
const legacyType = document.type;
|
||||
const folderId = document.folder?.id ?? document.folder ?? null;
|
||||
const common = {
|
||||
name: document.name,
|
||||
img: document.img,
|
||||
flags: foundry.utils.mergeObject(document.flags ?? {}, {
|
||||
[MODULE_ID]: {
|
||||
legacyType,
|
||||
migratedToMgt2e: MIGRATION_VERSION,
|
||||
},
|
||||
}),
|
||||
folder: folderId,
|
||||
sort: document.sort,
|
||||
ownership: document.ownership,
|
||||
};
|
||||
|
||||
switch (legacyType) {
|
||||
case 'armor':
|
||||
return {
|
||||
...common,
|
||||
type: 'armour',
|
||||
system: buildArmourSystem(document),
|
||||
};
|
||||
case 'weapon':
|
||||
return {
|
||||
...common,
|
||||
type: 'weapon',
|
||||
system: buildWeaponSystem(document),
|
||||
};
|
||||
case 'equipment':
|
||||
return {
|
||||
...common,
|
||||
type: isAugmentFolder(folderName) ? 'augment' : 'item',
|
||||
system: isAugmentFolder(folderName) ? buildAugmentSystem(document) : buildSimpleItemSystem(document),
|
||||
};
|
||||
case 'computer':
|
||||
return {
|
||||
...common,
|
||||
type: 'hardware',
|
||||
system: buildHardwareSystem(document),
|
||||
};
|
||||
case 'item':
|
||||
if (document.system?.subType === 'software') {
|
||||
return {
|
||||
...common,
|
||||
type: 'software',
|
||||
system: buildSoftwareSystem(document),
|
||||
};
|
||||
}
|
||||
return {
|
||||
...common,
|
||||
type: 'item',
|
||||
system: buildSimpleItemSystem(document),
|
||||
};
|
||||
case 'career':
|
||||
return {
|
||||
...common,
|
||||
type: 'item',
|
||||
system: buildReferenceItemSystem(document, 'Carriere', packName),
|
||||
};
|
||||
case 'talent':
|
||||
return {
|
||||
...common,
|
||||
type: 'item',
|
||||
system: buildReferenceItemSystem(document, document.system?.subType === 'psionic' ? 'Talent psionique' : 'Competence', packName),
|
||||
};
|
||||
case 'disease':
|
||||
return {
|
||||
...common,
|
||||
type: 'item',
|
||||
system: buildDiseaseItemSystem(document),
|
||||
};
|
||||
default:
|
||||
return {
|
||||
...common,
|
||||
type: 'item',
|
||||
system: buildReferenceItemSystem(document, legacyType, packName),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function buildWeaponSystem(document) {
|
||||
const system = document.system ?? {};
|
||||
const traits = normalizeTraits(system.traits);
|
||||
const melee = Boolean(system.range?.isMelee);
|
||||
|
||||
return {
|
||||
tl: normalizeTl(system.tl),
|
||||
weight: toNumber(system.weight),
|
||||
cost: toNumber(system.cost),
|
||||
notes: traits.notes,
|
||||
active: Boolean(system.equipped),
|
||||
quantity: toNumber(system.quantity, 1),
|
||||
status: system.trash ? 'broken' : null,
|
||||
legality: 9,
|
||||
weapon: {
|
||||
scale: 'traveller',
|
||||
range: melee ? 0 : toNumber(system.range?.value),
|
||||
minRange: 0,
|
||||
damage: normalizeDamage(system.damage),
|
||||
magazine: toNumber(system.magazine),
|
||||
ammo: toNumber(system.magazine),
|
||||
magazineCost: toNumber(system.magazineCost),
|
||||
characteristic: melee ? 'STR' : 'DEX',
|
||||
skill: inferWeaponSkillFromName(document.name, melee),
|
||||
parryBonus: 0,
|
||||
damageBonus: melee ? 'STR' : '',
|
||||
damageType: 'standard',
|
||||
attackBonus: 0,
|
||||
traits: traits.names,
|
||||
},
|
||||
description: formatDescription(system.description),
|
||||
};
|
||||
}
|
||||
|
||||
function buildArmourSystem(document) {
|
||||
const system = document.system ?? {};
|
||||
return {
|
||||
tl: normalizeTl(system.tl),
|
||||
weight: toNumber(system.weight),
|
||||
cost: toNumber(system.cost),
|
||||
notes: buildLines([
|
||||
system.requireSkillLevel != null ? `Combi requise: ${system.requireSkillLevel}` : '',
|
||||
]),
|
||||
active: Boolean(system.equipped),
|
||||
quantity: toNumber(system.quantity, 1),
|
||||
status: system.trash ? 'broken' : null,
|
||||
legality: 9,
|
||||
armour: {
|
||||
protection: toNumber(String(system.protection ?? '').replace(/[^\d-]/g, '')),
|
||||
otherProtection: 0,
|
||||
otherTypes: '',
|
||||
rad: toNumber(system.radiations),
|
||||
archaic: 0,
|
||||
skill: toNumber(system.requireSkillLevel) > 0 ? 'vaccsuit' : '',
|
||||
duration: 0,
|
||||
slots: 0,
|
||||
form: 'standard',
|
||||
layered: 0,
|
||||
ablat: 0,
|
||||
powered: Boolean(system.powered) ? 1 : 0,
|
||||
psi: 0,
|
||||
worn: Boolean(system.equipped) ? 1 : 0,
|
||||
},
|
||||
description: formatDescription(system.description),
|
||||
};
|
||||
}
|
||||
|
||||
function buildSimpleItemSystem(document) {
|
||||
const system = document.system ?? {};
|
||||
return {
|
||||
tl: normalizeTl(system.tl),
|
||||
weight: toNumber(system.weight),
|
||||
cost: toNumber(system.cost),
|
||||
notes: '',
|
||||
active: Boolean(system.equipped),
|
||||
quantity: toNumber(system.quantity, 1),
|
||||
status: system.trash ? 'broken' : null,
|
||||
legality: 9,
|
||||
description: formatDescription(system.description),
|
||||
};
|
||||
}
|
||||
|
||||
function buildAugmentSystem(document) {
|
||||
const system = buildSimpleItemSystem(document);
|
||||
return system;
|
||||
}
|
||||
|
||||
function buildHardwareSystem(document) {
|
||||
const system = document.system ?? {};
|
||||
return {
|
||||
tl: normalizeTl(system.tl),
|
||||
weight: toNumber(system.weight),
|
||||
cost: toNumber(system.cost),
|
||||
notes: buildLines([
|
||||
system.overload ? 'Surcharge: oui' : '',
|
||||
system.processing != null ? `Traitement: ${system.processing}` : '',
|
||||
system.processingUsed != null ? `Traitement utilise: ${system.processingUsed}` : '',
|
||||
]),
|
||||
active: false,
|
||||
quantity: toNumber(system.quantity, 1),
|
||||
status: system.trash ? 'broken' : null,
|
||||
legality: 9,
|
||||
hardware: {
|
||||
system: 'computer',
|
||||
tons: 0,
|
||||
power: toNumber(system.processing),
|
||||
rating: inferRating(document.name),
|
||||
variables: {
|
||||
max: 0,
|
||||
tl: normalizeTl(system.tl),
|
||||
cost: toNumber(system.cost),
|
||||
},
|
||||
},
|
||||
description: formatDescription(system.description),
|
||||
};
|
||||
}
|
||||
|
||||
function buildSoftwareSystem(document) {
|
||||
const system = document.system ?? {};
|
||||
return {
|
||||
quantity: toNumber(system.quantity, 1),
|
||||
tl: normalizeTl(system.tl),
|
||||
software: {
|
||||
bandwidth: toNumber(system.software?.bandwidth),
|
||||
},
|
||||
cost: toNumber(system.cost),
|
||||
description: formatDescription(system.description),
|
||||
};
|
||||
}
|
||||
|
||||
function buildReferenceItemSystem(document, category, packName) {
|
||||
const system = document.system ?? {};
|
||||
const isSkillReference = packName === 'competences';
|
||||
return {
|
||||
tl: normalizeTl(system.tl),
|
||||
weight: toNumber(system.weight),
|
||||
cost: toNumber(system.cost),
|
||||
notes: buildLines([
|
||||
isSkillReference ? 'Référence documentaire uniquement — les compétences de jeu utilisent désormais actor.system.skills et la localisation MGT2.Skills.*.' : '',
|
||||
category ? `Categorie legacy: ${category}` : '',
|
||||
system.subType ? `Sous-type legacy: ${system.subType}` : '',
|
||||
system.level != null ? `Niveau legacy: ${system.level}` : '',
|
||||
system.assignment ? `Affectations: ${system.assignment}` : '',
|
||||
]),
|
||||
active: false,
|
||||
quantity: toNumber(system.quantity, 1),
|
||||
status: null,
|
||||
legality: 9,
|
||||
description: isSkillReference
|
||||
? formatDescription([system.description, '<p><strong>Note mgt2e :</strong> cette entrée sert de référence documentaire. Les compétences jouables sont natives à la fiche de personnage `mgt2e`.</p>'].filter(Boolean).join('\n\n'))
|
||||
: formatDescription(system.description),
|
||||
};
|
||||
}
|
||||
|
||||
function buildDiseaseItemSystem(document) {
|
||||
const system = document.system ?? {};
|
||||
return {
|
||||
tl: '0',
|
||||
weight: 0,
|
||||
cost: 0,
|
||||
notes: buildLines([
|
||||
system.subType ? `Sous-type: ${system.subType}` : '',
|
||||
system.difficulty ? `Difficulte: ${system.difficulty}` : '',
|
||||
system.damage ? `Degats: ${system.damage}` : '',
|
||||
system.interval ? `Intervalle: ${system.interval}` : '',
|
||||
]),
|
||||
active: false,
|
||||
quantity: 1,
|
||||
status: null,
|
||||
legality: 9,
|
||||
description: formatDescription(system.description),
|
||||
};
|
||||
}
|
||||
|
||||
function isAugmentFolder(folderName) {
|
||||
return /augmentation/i.test(folderName ?? '');
|
||||
}
|
||||
|
||||
function normalizeTl(value) {
|
||||
const match = String(value ?? '').match(/(\d+)/);
|
||||
return match ? match[1] : '0';
|
||||
}
|
||||
|
||||
function normalizeDamage(value) {
|
||||
return String(value ?? '1D6').replace(/d/g, 'D');
|
||||
}
|
||||
|
||||
function toNumber(value, fallback = 0) {
|
||||
const parsed = Number.parseInt(String(value ?? ''), 10);
|
||||
return Number.isFinite(parsed) ? parsed : fallback;
|
||||
}
|
||||
|
||||
function inferRating(name) {
|
||||
const match = String(name ?? '').match(/\/(\d+)/);
|
||||
return match ? Number.parseInt(match[1], 10) : 0;
|
||||
}
|
||||
|
||||
function normalizeTraits(traits) {
|
||||
if (!Array.isArray(traits) || !traits.length) return { names: '', notes: '' };
|
||||
|
||||
const names = traits
|
||||
.map((trait) => trait?.name ?? trait)
|
||||
.filter(Boolean)
|
||||
.join(', ');
|
||||
const notes = traits
|
||||
.filter((trait) => trait?.description)
|
||||
.map((trait) => `${trait.name}: ${trait.description}`)
|
||||
.join('\n');
|
||||
|
||||
return { names, notes };
|
||||
}
|
||||
|
||||
function formatDescription(value) {
|
||||
const text = String(value ?? '').trim();
|
||||
if (!text) return '';
|
||||
if (text.includes('<')) return text;
|
||||
|
||||
const paragraphs = text
|
||||
.split(/\n{2,}/)
|
||||
.map((part) => part.trim())
|
||||
.filter(Boolean)
|
||||
.map((part) => `<p>${part.replace(/\n/g, '<br>')}</p>`);
|
||||
|
||||
return paragraphs.join('');
|
||||
}
|
||||
|
||||
function buildLines(lines) {
|
||||
return lines.filter(Boolean).join('\n');
|
||||
}
|
||||
Reference in New Issue
Block a user