Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 24521f593f | |||
| a2f472f947 | |||
| f3d9c18028 | |||
| e536e24d6b | |||
| fcc8ad5c55 |
10
module.json
10
module.json
@@ -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.0",
|
||||
"version": "1.0.4",
|
||||
"author": "Booga",
|
||||
"minimumCoreVersion": "10",
|
||||
"compatibleCoreVersion": "11",
|
||||
"minimumCoreVersion": "11",
|
||||
"compatibleCoreVersion": "12",
|
||||
"esmodules": ["shadowdarklings-importer.js"],
|
||||
"systems": ["shadowdark"],
|
||||
"manifest": "https://yourdomain.com/path/to/module.json",
|
||||
"download": "https://yourdomain.com/path/to/module.zip"
|
||||
"manifest": "https://g.kht.dev/kyle/shadowdark-importer/module.json",
|
||||
"download": "https://g.kht.dev/kyle/shadowdark-importer/archive/v1.0.4.zip"
|
||||
}
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user