167 lines
5.0 KiB
JavaScript
167 lines
5.0 KiB
JavaScript
// 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 = $(
|
|
`<button class="shadowdarklings-importer"><i class="fas fa-file-import"></i> Shadowdarklings Import</button>`
|
|
);
|
|
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: `
|
|
<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;
|
|
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.");
|
|
}
|