// shadowdarklings-importer.js Hooks.once("ready", function () { // Add button to Actors Directory Hooks.on("renderActorDirectory", (app, html, data) => { appendImportButton(html, app, "actor"); }); // Add button to Items Directory Hooks.on("renderItemDirectory", (app, html, data) => { appendImportButton(html, app, "item"); }); }); function appendImportButton(html, app, type) { const importBtn = $( `` ); importBtn.on("click", async () => { const dialog = new ShadowdarklingsImportDialog(type, app); dialog.render(true); }); html.find(".directory-footer").append(importBtn); } // Upload dialog class ShadowdarklingsImportDialog extends Dialog { constructor(type, app) { super({ title: `Import Shadowdarklings ${type === "actor" ? "Character/Monster" : "Item"}`, content: `
`, buttons: { import: { icon: '', label: "Import", callback: (html) => this.importJSON(html) }, cancel: { icon: '', label: "Cancel" } }, default: "import" }); this.type = type; this.app = app; } async importJSON(html) { const file = html.find('input[name="json"]')[0]?.files[0]; if (!file) { ui.notifications.error("No file selected!"); return; } let json; try { json = JSON.parse(await file.text()); } catch (err) { ui.notifications.error("Invalid JSON file."); return; } if (this.type === "actor") { return importShadowdarklingsActor(json, this.app); } else { return importShadowdarklingsItem(json, this.app); } } } // Main actor importer async function importShadowdarklingsActor(data, app) { // Use system-defined actor types: 'pc' (player), 'npc' (monsters/opponents) // Try to discern if this is a PC or NPC/Monster. let actorType = "npc"; // If class or level is present, it's likely a PC if (data.class || data.level || data.background || data.player) actorType = "pc"; // Allowed actor types const allowedTypes = game.system.model.Actor ? Object.keys(game.system.model.Actor) : ["pc","npc"]; if (!allowedTypes.includes(actorType)) actorType = allowedTypes[0]; // Fallback // Setup the document data const actorData = { name: data.name || "Imported Character", type: actorType, system: { abilities: { str: { value: data.str }, dex: { value: data.dex }, int: { value: data.int }, wis: { value: data.wis }, con: { value: data.con }, cha: { value: data.cha } }, ac: { value: data.ac }, hp: { value: data.hp, max: data.hp || data.maxHp, min: 0 }, level: { value: data.level }, class: { value: data.class }, ancestry: { value: data.race }, alignment: { value: data.alignment } // Extend as needed for your Shadowdark system version }, // Optionally add image // img: data.img || "icons/svg/mystery-man.svg" }; // Try inventory import (if system supports embedded items in actors) if (Array.isArray(data.inventory)) { actorData.items = data.inventory.filter(i=>i.name).map(itm => ({ name: itm.name, type: "equipment", // Or "gear" or your actual item type in Shadowdark system: { description: { value: itm.description || "" }, quantity: itm.quantity || 1, value: itm.value || "", weight: itm.weight || "" } })); } // Create the actor using v12 Documents API try { const created = await Actor.createDocuments([actorData], {parent: game.actors}); ui.notifications.info(`${actorData.name} imported successfully!`); // Optionally, highlight/select the imported actor if (created.length && app) { app._lastSelected = [created[0].id]; app.render(); } } catch (e) { console.error(e); ui.notifications.error("Actor import failed."); } } // Items (single or list) async function importShadowdarklingsItem(data, app) { // Accept single or array of items const items = Array.isArray(data) ? data : [data]; let created = []; for (let itm of items) { if (!itm.name) continue; const itemData = { name: itm.name, type: itm.type || "equipment", // Check your Shadowdark item types! system: { description: { value: itm.description || "" }, quantity: itm.quantity || 1 } }; try { const docs = await Item.createDocuments([itemData], {parent: game.items}); created.push(...docs); } catch (e) { console.error(e); ui.notifications.warn(`Failed to import item: ${itm.name}`); } } if (created.length > 0) ui.notifications.info("Items imported."); }