|
|
|
|
@@ -1,5 +1,5 @@
|
|
|
|
|
// shadowdarklings-importer.js
|
|
|
|
|
Hooks.on("ready", function () {
|
|
|
|
|
Hooks.once("ready", function () {
|
|
|
|
|
// Add button to Actors Directory
|
|
|
|
|
Hooks.on("renderActorDirectory", (app, html, data) => {
|
|
|
|
|
appendImportButton(html, app, "actor");
|
|
|
|
|
@@ -15,16 +15,15 @@ function appendImportButton(html, app, type) {
|
|
|
|
|
`<button class="shadowdarklings-importer"><i class="fas fa-file-import"></i> Shadowdarklings Import</button>`
|
|
|
|
|
);
|
|
|
|
|
importBtn.on("click", async () => {
|
|
|
|
|
const dialog = new ShadowdarklingsImportDialog(type);
|
|
|
|
|
const dialog = new ShadowdarklingsImportDialog(type, app);
|
|
|
|
|
dialog.render(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
html.find(".directory-footer").append(importBtn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A dialog window to upload JSON and start the import process
|
|
|
|
|
// Upload dialog
|
|
|
|
|
class ShadowdarklingsImportDialog extends Dialog {
|
|
|
|
|
constructor(type) {
|
|
|
|
|
constructor(type, app) {
|
|
|
|
|
super({
|
|
|
|
|
title: `Import Shadowdarklings ${type === "actor" ? "Character/Monster" : "Item"}`,
|
|
|
|
|
content: `
|
|
|
|
|
@@ -49,6 +48,7 @@ class ShadowdarklingsImportDialog extends Dialog {
|
|
|
|
|
default: "import"
|
|
|
|
|
});
|
|
|
|
|
this.type = type;
|
|
|
|
|
this.app = app;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async importJSON(html) {
|
|
|
|
|
@@ -65,27 +65,30 @@ class ShadowdarklingsImportDialog extends Dialog {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Dispatch to appropriate handler
|
|
|
|
|
if (this.type === "actor") {
|
|
|
|
|
return importShadowdarklingsActor(json);
|
|
|
|
|
return importShadowdarklingsActor(json, this.app);
|
|
|
|
|
} else {
|
|
|
|
|
return importShadowdarklingsItem(json);
|
|
|
|
|
return importShadowdarklingsItem(json, this.app);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
// 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";
|
|
|
|
|
|
|
|
|
|
// Very basic mapping, adjust as needed
|
|
|
|
|
// 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: data.class ? "character" : "npc", // Guess by "class" being present
|
|
|
|
|
type: actorType,
|
|
|
|
|
system: {
|
|
|
|
|
abilities: {
|
|
|
|
|
str: { value: data.str },
|
|
|
|
|
@@ -96,60 +99,68 @@ async function importShadowdarklingsActor(data) {
|
|
|
|
|
cha: { value: data.cha }
|
|
|
|
|
},
|
|
|
|
|
ac: { value: data.ac },
|
|
|
|
|
hp: { value: data.hp, max: data.hp },
|
|
|
|
|
hp: { value: data.hp, max: data.hp || data.maxHp, min: 0 },
|
|
|
|
|
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
|
|
|
|
|
ancestry: { value: data.race },
|
|
|
|
|
alignment: { value: data.alignment }
|
|
|
|
|
// Extend as needed for your Shadowdark system version
|
|
|
|
|
},
|
|
|
|
|
// Optionally add avatar/portrait: img: data.img
|
|
|
|
|
// Optionally import inventory as embedded items, etc.
|
|
|
|
|
// Optionally add image
|
|
|
|
|
// img: data.img || "icons/svg/mystery-man.svg"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Try to import inventory if present
|
|
|
|
|
// Try inventory import (if system supports embedded items in actors)
|
|
|
|
|
if (Array.isArray(data.inventory)) {
|
|
|
|
|
actorData.items = data.inventory.map(itm => ({
|
|
|
|
|
actorData.items = data.inventory.filter(i=>i.name).map(itm => ({
|
|
|
|
|
name: itm.name,
|
|
|
|
|
type: "equipment", // Guess, or use your actual item types
|
|
|
|
|
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 || "",
|
|
|
|
|
weight: itm.weight || ""
|
|
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create the actor in the current folder
|
|
|
|
|
// Create the actor using v12 Documents API
|
|
|
|
|
try {
|
|
|
|
|
await Actor.create(actorData);
|
|
|
|
|
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.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function importShadowdarklingsItem(data) {
|
|
|
|
|
// 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",
|
|
|
|
|
type: itm.type || "equipment", // Check your Shadowdark item types!
|
|
|
|
|
system: {
|
|
|
|
|
description: { value: itm.description || "" },
|
|
|
|
|
// Add other fields as needed
|
|
|
|
|
},
|
|
|
|
|
quantity: itm.quantity || 1
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
try {
|
|
|
|
|
await Item.create(itemData);
|
|
|
|
|
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}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ui.notifications.info("Items imported.");
|
|
|
|
|
if (created.length > 0) ui.notifications.info("Items imported.");
|
|
|
|
|
}
|
|
|
|
|
|