Files
shadowdark-importer/shadowdarklings-importer.js

156 lines
4.4 KiB
JavaScript
Raw Normal View History

2025-05-16 05:56:22 -05:00
// shadowdarklings-importer.js
Hooks.on("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 = $(
`<button class="shadowdarklings-importer"><i class="fas fa-file-import"></i> Shadowdarklings Import</button>`
);
importBtn.on("click", async () => {
const dialog = new ShadowdarklingsImportDialog(type);
dialog.render(true);
});
html.find(".directory-footer").append(importBtn);
}
// A dialog window to upload JSON and start the import process
class ShadowdarklingsImportDialog extends Dialog {
constructor(type) {
super({
title: `Import Shadowdarklings ${type === "actor" ? "Character/Monster" : "Item"}`,
content: `
<form>
<div class="form-group">
<label>Upload Shadowdarklings JSON:</label>
<input type="file" name="json" accept="application/json"/>
</div>
</form>
`,
buttons: {
import: {
icon: '<i class="fas fa-file-import"></i>',
label: "Import",
callback: (html) => this.importJSON(html)
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: "Cancel"
}
},
default: "import"
});
this.type = type;
}
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;
}
// Dispatch to appropriate handler
if (this.type === "actor") {
return importShadowdarklingsActor(json);
} else {
return importShadowdarklingsItem(json);
}
}
}
// Example mapping function for actor
async function importShadowdarklingsActor(data) {
// Try to discern if this is a character or monster format
if (!data.name) {
ui.notifications.error("This JSON does not look like a Shadowdark character.");
return;
}
// Very basic mapping, adjust as needed
const actorData = {
name: data.name || "Imported Character",
type: data.class ? "character" : "npc", // Guess by "class" being present
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 },
level: { value: data.level },
class: { value: data.class },
race: { value: data.race },
alignment: { value: data.alignment },
// Add more mappings as fits your needs and data
},
// Optionally add avatar/portrait: img: data.img
// Optionally import inventory as embedded items, etc.
};
// Try to import inventory if present
if (Array.isArray(data.inventory)) {
actorData.items = data.inventory.map(itm => ({
name: itm.name,
type: "equipment", // Guess, or use your actual item types
system: {
description: { value: itm.description || "" },
quantity: itm.quantity || 1,
value: itm.value || "",
weight: itm.weight || "",
}
}));
}
// Create the actor in the current folder
try {
await Actor.create(actorData);
ui.notifications.info(`${actorData.name} imported successfully!`);
} catch (e) {
console.error(e);
ui.notifications.error("Actor import failed.");
}
}
async function importShadowdarklingsItem(data) {
// Accept single or array of items
const items = Array.isArray(data) ? data : [data];
for (let itm of items) {
if (!itm.name) continue;
const itemData = {
name: itm.name,
type: itm.type || "equipment",
system: {
description: { value: itm.description || "" },
// Add other fields as needed
},
};
try {
await Item.create(itemData);
} catch (e) {
console.error(e);
ui.notifications.warn(`Failed to import item: ${itm.name}`);
}
}
ui.notifications.info("Items imported.");
}