2 Commits

Author SHA1 Message Date
35078e9e26 updated with correct module 2025-05-16 15:24:17 -05:00
24521f593f updated js for v12 2025-05-16 06:21:19 -05:00
2 changed files with 49 additions and 38 deletions

View File

@@ -2,12 +2,12 @@
"name": "shadowdarklings-importer",
"title": "Shadowdarklings.net Importer",
"description": "Import JSON characters and items from shadowdarklings.net into Foundry VTT.",
"version": "1.0.3",
"version": "1.0.5",
"author": "Booga",
"minimumCoreVersion": "11",
"compatibleCoreVersion": "12",
"esmodules": ["shadowdarklings-importer.js"],
"systems": ["shadowdark"],
"manifest": "https://g.kht.dev/kyle/shadowdark-importer/module.json",
"download": "https://g.kht.dev/kyle/shadowdark-importer/archive/v1.0.3.zip"
"manifest": "https://g.kht.dev/kyle/shadowdark-importer/raw/branch/main/module.json",
"download": "https://g.kht.dev/kyle/shadowdark-importer/archive/v1.0.5.zip"
}

View File

@@ -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.");
}