Appliquer le relink à tous les personnages du monde ?
", buttons: { yes: { label: "Oui", callback: () => resolve(true) }, no: { label: "Non", callback: () => resolve(false) } }, default: "no" }).render(true); }); if(!proceed) return; actors = game.actors.filter(a=>a.type==="character"); } if(!actors.length){ ui.notifications.warn("Aucun acteur cible."); return; } const packs = game.packs.filter(p=>p.documentName==="Item" && (/cthack/i.test(p.collection)||/cthack/i.test(p.metadata?.system||p.metadata?.package||""))); if(!packs.length){ ui.notifications.warn("Aucun compendium d’Items CtHack trouvé."); return; } const byKey=Object.fromEntries(TYPES.map(t=>[t,new Map()])); const byName=Object.fromEntries(TYPES.map(t=>[t,new Map()])); for(const pack of packs){ const idx=await pack.getIndex({fields:["name","type","system.key"]}); for(const it of idx){ const t=TYPES.includes(it.type)?it.type:"item"; const uuid="Compendium."+pack.collection+"."+it._id; const k=(it.system?.key??"").toString().toUpperCase(); if(k){ const arrK=byKey[t].get(k)||[]; arrK.push(uuid); byKey[t].set(k,arrK); } const nk=norm(it.name); const arrN=byName[t].get(nk)||[]; arrN.push(uuid); byName[t].set(nk,arrN); } } const docCache=new Map(); async function loadUuid(u){ if(docCache.has(u)) return docCache.get(u); const d=await fromUuid(u); if(d) docCache.set(u,d); return d; } async function findMatch(item){ const tPref=TYPES.includes(item.type)?item.type:"item"; const typeHint=String(item.flags?.lfdc?.typeHint||"").toLowerCase(); const keyHint=(item.system?.key||item.flags?.lfdc?.key||"").toString().toUpperCase(); const nameHit=norm(item.name); const base=TYPES.filter(t=>t!==tPref); const order=TYPES.includes(typeHint)?[typeHint,tPref,...base.filter(t=>t!==typeHint)]:[tPref,...base]; if(keyHint){ for(const t of order){ const arr=byKey[t].get(keyHint); if(arr?.length) return await loadUuid(arr[0]); } } for(const t of order){ const arr=byName[t].get(nameHit); if(arr?.length) return await loadUuid(arr[0]); } for(const t of TYPES){ const arr=byName[t].get(nameHit); if(arr?.length) return await loadUuid(arr[0]); } return null; } let total=0,replaced=0,missed=0; const misses=[]; for(const actor of actors){ const items=actor.items.filter(i=>TYPES.includes(i.type)); total+=items.length; for(const it of items){ const comp=await findMatch(it); if(!comp){ missed++; misses.push(actor.name+" › "+it.name+" ("+it.type+")"); continue; } const data=comp.toObject(); data._id=it.id; try{ if(it.system?.uses && data.system?.uses){ data.system.uses=foundry.utils.mergeObject(data.system.uses,it.system.uses,{overwrite:false}); } }catch(e){} await it.update(data); await it.update({"flags.core.sourceId":comp.uuid}); replaced++; } } const msg="Relink CtHack: "+replaced+"/"+total+" items remplacés, "+missed+" sans correspondance."; ui.notifications.info(msg); console.log(msg); if(misses.length){ console.group("Items sans correspondance"); for(const m of misses) console.log(m); console.groupEnd(); }