From 3476098020856eae9b2f6bec83f49f1f23b2f55f Mon Sep 17 00:00:00 2001 From: Abraham Nassiff Date: Sun, 4 Jun 2023 11:49:39 -0500 Subject: [PATCH 1/3] Import JSON from Mothership Companion --- module/mosh.js | 392 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 392 insertions(+) diff --git a/module/mosh.js b/module/mosh.js index 8017418..68298d8 100644 --- a/module/mosh.js +++ b/module/mosh.js @@ -105,6 +105,17 @@ Hooks.once("ready", async function () { } }) +Hooks.on('renderSidebarTab', async (app, html) => { + if (app.options.id == "actors") { + let button = $(``); + button.click(function() { + d.render(true); + }); + html.find(".directory-footer").append(button); + } +}); + + /* -------------------------------------------- */ /* Hotbar Macros */ @@ -145,6 +156,387 @@ async function createMothershipMacro(data, slot) { } + +/* -------------------------------------------- */ +/* Actor from JSON */ +/* -------------------------------------------- */ +let skillValues = { + "archeology": {"value":10, "rank": "Trained"}, + "art": {"value":10, "rank": "Trained"}, + "athletics": {"value":10, "rank": "Trained"}, + "botany": {"value":10, "rank": "Trained"}, + "chemistry": {"value":10, "rank": "Trained"}, + "computers": {"value":10, "rank": "Trained"}, + "geology": {"value":10, "rank": "Trained"}, + "industrialequipment": {"value":10, "rank": "Trained"}, + "juryrigging": {"value":10, "rank": "Trained"}, + "linguistics": {"value":10, "rank": "Trained"}, + "mathematics": {"value":10, "rank": "Trained"}, + "militarytraining": {"value":10, "rank": "Trained"}, + "rimwise": {"value":10, "rank": "Trained"}, + "theology": {"value":10, "rank": "Trained"}, + "zerog": {"value":10, "rank": "Trained"}, + "zoology": {"value":10, "rank": "Trained"}, + "asteroidmining": {"value":15, "rank": "Expert"}, + "ecology": {"value":15, "rank": "Expert"}, + "explosives": {"value":15, "rank": "Expert"}, + "fieldmedicine": {"value":15, "rank": "Expert"}, + "firearms": {"value":15, "rank": "Expert"}, + "hacking": {"value":15, "rank": "Expert"}, + "handtohandcombat": {"value":15, "rank": "Expert"}, + "mechanicalrepair": {"value":15, "rank": "Expert"}, + "mysticism": {"value":15, "rank": "Expert"}, + "pathology": {"value":15, "rank": "Expert"}, + "pharmacology": {"value":15, "rank": "Expert"}, + "physics": {"value":15, "rank": "Expert"}, + "piloting": {"value":15, "rank": "Expert"}, + "psychology": {"value":15, "rank": "Expert"}, + "tactics": {"value":15, "rank": "Expert"}, + "wildernesssurvival": {"value":15, "rank": "Expert"}, + "artificialintenligence": {"value":20, "rank": "Master"}, + "command": {"value":20, "rank": "Master"}, + "cybernetics": {"value":20, "rank": "Master"}, + "engineering": {"value":20, "rank": "Master"}, + "exobiology": {"value":20, "rank": "Master"}, + "hyperspace": {"value":20, "rank": "Master"}, + "planetology": {"value":20, "rank": "Master"}, + "robotics": {"value":20, "rank": "Master"}, + "sophontology": {"value":20, "rank": "Master"}, + "surgery": {"value":20, "rank": "Master"}, + "xenoesoterism": {"value":20, "rank": "Master"}, +} + +let conditions = { + "adrenalinerush": "[+] on all rolls for the next 2d10 minutes. Reduce your Stress by 1d5.", + "anxious": "Gain 1 Stress.", + "jumpy": "Gain 1 Stress. All Close crewmembers gain 2 Stress.", + "overwhelmed": "All actions at [-] for 1d10 minutes. Permanently raise your Minimum Stress by 1.", + "coward": "Gain a new Condition: You must make a Fear Save to engage in violence or flee.", + "frightened": "Gain a new Condition: Phobia: When encountering your Phobia make a Fear Save [-] or gain 1d5 Stress.", + "nightmares": "Gain a new Condition: Sleep is difficult, gain [-] on all Rest Saves.", + "lossofconfidence": "Gain a new Condition: Choose one of your Skills and lose that Skill's bonus.", + "deflated": "Gain a new Condition: Whenever a Close crewmember fails a Save, gain 1 Stress.", + "doomed": "Gain a new Condition: You feel cursed and unlucky. All Critical Successes are instead Critical Failures.", + "paranoid": "For the next week, whenever someone joins your group (even if they only left for a short period of time), make a Fear Save or gain 1 Stress.", + "haunted": "Gain a new Condition: Something starts visiting you at night. In your dreams. Out of the corner of your eye. And soon it will start making demands.", + "deathwish": "For the next 24 hours, whenever you encounter a stranger or known enemy, you must make a Sanity Save or immediately attack them.", + "propheticvision": "You immediately experience an intense hallucination or vision of an impending terror or horrific event. Gain 1 Stress.", + "catatonic": "Become unresponsive and unmoving for 2d10 minutes. Reduce Stress by 1d10.", + "rage": "Immediately attack the closest crewmember until you inflict at least 2d10 DMG. If there is no crewmember Close, you attack your surrounding environment.", + "spiraling": "Gain a new Condition: You make Panic Checks with Disadvantage.", + "compoundingproblems": "Roll twice on this table. Permanently raise your Minimum Stress by 1.", + "heartattack": "Permanently lose 1 Wound. Gain [-] on all rolls for 1d10 hours. Permanently raise your Minimum Stress by 1.", + "collapse": "You no longer control this character. Hand your sheet to the Warden and roll up a new character to play." +} + +async function createActorFromJson(jsonData) { + let actorData; + let newActor; + // if (actorData.armor.length) { + // newActor.system.stats.armor = { + // "value": actorData.armor.armorPoints, + // "label": Armor + // } + // } + try { + actorData = JSON.parse(jsonData); + newActor = { + "name": actorData.name, + "type": "character", + "img": "icons/svg/mystery-man.svg", + "system": { + "health": { + "value": actorData.health, + "max": actorData.maxHealth, + "min": 0 + }, + "hits": { + "value": actorData.wounds, + "max": actorData.maxWounds + }, + "biography": "", + "notes": "", + "weight": {"current": 0, "capacity": 0}, + "settings": {"useCalm": false}, + "class": { + "value": actorData.characterClass.charAt(0).toUpperCase() + actorData.characterClass.slice(1) + }, + "rank": {"value": ""}, + "pronouns": {"value": actorData.pronouns}, + "credits": {"value": actorData.credits}, + "stressdesc": {"value": actorData.traumaResponse}, + "xp": { "value": 0, "html": 0, "selectedSkill": ""}, + "stressdesc": {"value": actorData.traumaResponse}, + "attributes": {"level": { "value": actorData.highScore }}, + "stats": { + "strength": { + "value": actorData.strength, + "label": "Strength", + "mod": null + }, + "speed": { + "value": actorData.speed, + "label": "Speed", + "mod": null + }, + "intellect": { + "value": actorData.intellect, + "label": "Intellect", + "mod": null + }, + "combat": { + "value": actorData.combat, + "label": "Combat", + "mod": null + }, + "sanity": { + "value": actorData.sanity, + "label": "Sanity" + }, + "fear": { + "value": actorData.fear, + "label": "Fear" + }, + "body": { + "value": actorData.body, + "label": "Body" + } + }, + "other": { + "stress": { + "value": actorData.stress, + "min": actorData.minStress, + "label": "Stress" + }, + "resolve": 0 + } + }, + "prototypeToken": { + "name": actorData.name, + "displayName": 0, + "actorLink": false, + "texture": { + "src": "icons/svg/mystery-man.svg", + "scaleX": 1, + "scaleY": 1, + "offsetX": 0, + "offsetY": 0, + "rotation": 0, + "tint": null + }, + "width": 1, + "height": 1, + "lockRotation": false, + "rotation": 0, + "alpha": 1, + "disposition": -1, + "displayBars": 0, + "bar1": { + "attribute": "health" + }, + "bar2": { + "attribute": "power" + }, + "light": { + "alpha": 0.5, + "angle": 360, + "bright": 0, + "color": null, + "coloration": 1, + "dim": 0, + "attenuation": 0.5, + "luminosity": 0.5, + "saturation": 0, + "contrast": 0, + "shadows": 0, + "animation": { + "type": null, + "speed": 5, + "intensity": 5, + "reverse": false + }, + "darkness": { + "min": 0, + "max": 1 + } + }, + "sight": { + "enabled": false, + "range": null, + "angle": 360, + "visionMode": "basic", + "color": null, + "attenuation": 0.1, + "brightness": 0, + "saturation": 0, + "contrast": 0 + }, + "detectionModes": [], + "flags": {}, + "randomImg": false + } + }; + var items = []; + if (actorData.trinket) { + items.push({ + "name": "Trinket: " + actorData.trinket, + "type": "item" + }) + } + if (actorData.patch) { + items.push({ + "name": "Patch: " + actorData.patch, + "type": "item" + }) + } + // Equipment + for (let i = 0; i < actorData.equipment.length; i++) { + items.push({ + "name": actorData.equipment[i].name, + "type": "item", + "system": { + "description": actorData.equipment[i].description, + "cost": actorData.equipment[i].cost, + "quantity": actorData.equipment[i].quantity + }, + "img": "icons/svg/item-bag.svg", + }) + } + // Items + for (let i = 0; i < actorData.items.length; i++) { + items.push({ + "name": actorData.items[i].title, + "type": "item", + "system": { + "description": actorData.items[i].description, + "cost": actorData.items[i].cost, + "quantity": actorData.items[i].quantity + }, + "img": "icons/svg/item-bag.svg", + }) + } + // Armor + for (let i = 0; i < actorData.armor.length; i++) { + items.push({ + "name": actorData.armor[i].name, + "type": "armor", + "system": { + "description": actorData.armor[i].notes, + "cost": actorData.armor[i].cost, + "bonus": actorData.armor[i].armorPoints, + "equipped": actorData.armor[i].equipped + }, + "img": "icons/svg/item-bag.svg", + }) + } + // Weapons + for (let i = 0; i < actorData.weapons.length; i++) { + items.push({ + "name": actorData.weapons[i].weaponType, + "type": "weapon", + "system": { + "description": actorData.weapons[i].special, + "cost": actorData.weapons[i].cost, + "ranges": { + "short": 0, + "medium": 0, + "long": 0, + "value": actorData.weapons[i].weaponRange + }, + "equipped": actorData.weapons[i].equipped, + "critEffect": actorData.weapons[i].critical, + "shots": actorData.weapons[i].shots, + "curShots": actorData.weapons[i].shots, + "ammo": actorData.weapons[i].magazines, + "shotsPerFire": "1", + "useAmmo": false, + "ammoType": "", + "critDmg": actorData.weapons[i].critical, + "critEffect": "", + "damage": actorData.weapons[i].damageString + }, + "img": "icons/svg/item-bag.svg", + }) + } + // Skills + for (let i = 0; i < actorData.skills.length; i++) { + let words = actorData.skills[i].split(/(?=[A-Z])/); + let skillName = words.map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' '); + items.push({ + "name": skillName, + "type": "skill", + "system": { + "description": "", + "bonus": skillValues[actorData.skills[i].toLowerCase()].value, + "rank": skillValues[actorData.skills[i].toLowerCase()].rank + }, + "img": "icons/svg/item-bag.svg", + }) + } + // Conditions + for (let i = 0; i < actorData.conditions.length; i++) { + let conName = actorData.conditions[i].conditionType; + let words = conName.split(/(?=[A-Z])/); + let name = words.map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' '); + if (actorData.characterClass == "android" && conName.toLowerCase() == "heartattack") { + name = "Short Circuit" + } + items.push({ + "name": name, + "type": "condition", + "system": { + "description": conditions[conName.toLowerCase()], + "treatment": {"value": 0, "html": ""} + }, + "img": "icons/svg/item-bag.svg", + }) + } + newActor.items = items + + + } catch(err) { + console.error(err); + ui.notifications.error("Invalid JSON data"); + return; + } + + // Ensure the type of the actor (e.g., 'character') is correctly set according to your system + newActor.type = 'character'; + // Here we assume the actorData structure is correctly formed according to your system needs + + // You might need additional checks/transformations depending on the JSON data structure + + try { + await Actor.create(newActor); + ui.notifications.info("Actor created successfully"); + } catch(err) { + console.error(err); + ui.notifications.error("Failed to create actor"); + } +} + +let d = new Dialog({ + title: "Create Actor from JSON", + content: `

Paste your JSON data below:

`, + buttons: { + save: { + icon: '', + label: "Create", + callback: (html) => { + const jsonData = html.find('#json-data').val(); + createActorFromJson(jsonData); + } + }, + cancel: { + icon: '', + label: "Cancel" + } + }, + default: "save" +}); +d.render(true); + + /** * Roll Macro from a Weapon. * @param {string} itemName From 18ac3e152982c743dee681a1ade3c61df749eb6d Mon Sep 17 00:00:00 2001 From: Abraham Nassiff Date: Sun, 4 Jun 2023 11:57:08 -0500 Subject: [PATCH 2/3] Formatting and extra comments --- module/mosh.js | 522 +++++++++++++++++++++---------------------------- 1 file changed, 220 insertions(+), 302 deletions(-) diff --git a/module/mosh.js b/module/mosh.js index 68298d8..eb9a60b 100644 --- a/module/mosh.js +++ b/module/mosh.js @@ -31,8 +31,8 @@ Hooks.once('init', async function () { }; // Define custom Entity classes - CONFIG.Actor.documentClass = MothershipActor; - CONFIG.Item.documentClass = MothershipItem; + CONFIG.Actor.documentClass = MothershipActor; + CONFIG.Item.documentClass = MothershipItem; // Register sheet application classes @@ -80,7 +80,7 @@ Hooks.once("ready", async function () { /** * Set default values for new actors' tokens */ - Hooks.on("preCreateActor", (document, createData, options, userId) => { +Hooks.on("preCreateActor", (document, createData, options, userId) => { let disposition = CONST.TOKEN_DISPOSITIONS.NEUTRAL; if (createData.type == "creature") { @@ -108,7 +108,7 @@ Hooks.once("ready", async function () { Hooks.on('renderSidebarTab', async (app, html) => { if (app.options.id == "actors") { let button = $(``); - button.click(function() { + button.click(function () { d.render(true); }); html.find(".directory-footer").append(button); @@ -160,50 +160,51 @@ async function createMothershipMacro(data, slot) { /* -------------------------------------------- */ /* Actor from JSON */ /* -------------------------------------------- */ +// If there's a better place for these, please do move them let skillValues = { - "archeology": {"value":10, "rank": "Trained"}, - "art": {"value":10, "rank": "Trained"}, - "athletics": {"value":10, "rank": "Trained"}, - "botany": {"value":10, "rank": "Trained"}, - "chemistry": {"value":10, "rank": "Trained"}, - "computers": {"value":10, "rank": "Trained"}, - "geology": {"value":10, "rank": "Trained"}, - "industrialequipment": {"value":10, "rank": "Trained"}, - "juryrigging": {"value":10, "rank": "Trained"}, - "linguistics": {"value":10, "rank": "Trained"}, - "mathematics": {"value":10, "rank": "Trained"}, - "militarytraining": {"value":10, "rank": "Trained"}, - "rimwise": {"value":10, "rank": "Trained"}, - "theology": {"value":10, "rank": "Trained"}, - "zerog": {"value":10, "rank": "Trained"}, - "zoology": {"value":10, "rank": "Trained"}, - "asteroidmining": {"value":15, "rank": "Expert"}, - "ecology": {"value":15, "rank": "Expert"}, - "explosives": {"value":15, "rank": "Expert"}, - "fieldmedicine": {"value":15, "rank": "Expert"}, - "firearms": {"value":15, "rank": "Expert"}, - "hacking": {"value":15, "rank": "Expert"}, - "handtohandcombat": {"value":15, "rank": "Expert"}, - "mechanicalrepair": {"value":15, "rank": "Expert"}, - "mysticism": {"value":15, "rank": "Expert"}, - "pathology": {"value":15, "rank": "Expert"}, - "pharmacology": {"value":15, "rank": "Expert"}, - "physics": {"value":15, "rank": "Expert"}, - "piloting": {"value":15, "rank": "Expert"}, - "psychology": {"value":15, "rank": "Expert"}, - "tactics": {"value":15, "rank": "Expert"}, - "wildernesssurvival": {"value":15, "rank": "Expert"}, - "artificialintenligence": {"value":20, "rank": "Master"}, - "command": {"value":20, "rank": "Master"}, - "cybernetics": {"value":20, "rank": "Master"}, - "engineering": {"value":20, "rank": "Master"}, - "exobiology": {"value":20, "rank": "Master"}, - "hyperspace": {"value":20, "rank": "Master"}, - "planetology": {"value":20, "rank": "Master"}, - "robotics": {"value":20, "rank": "Master"}, - "sophontology": {"value":20, "rank": "Master"}, - "surgery": {"value":20, "rank": "Master"}, - "xenoesoterism": {"value":20, "rank": "Master"}, + "archeology": { "value": 10, "rank": "Trained" }, + "art": { "value": 10, "rank": "Trained" }, + "athletics": { "value": 10, "rank": "Trained" }, + "botany": { "value": 10, "rank": "Trained" }, + "chemistry": { "value": 10, "rank": "Trained" }, + "computers": { "value": 10, "rank": "Trained" }, + "geology": { "value": 10, "rank": "Trained" }, + "industrialequipment": { "value": 10, "rank": "Trained" }, + "juryrigging": { "value": 10, "rank": "Trained" }, + "linguistics": { "value": 10, "rank": "Trained" }, + "mathematics": { "value": 10, "rank": "Trained" }, + "militarytraining": { "value": 10, "rank": "Trained" }, + "rimwise": { "value": 10, "rank": "Trained" }, + "theology": { "value": 10, "rank": "Trained" }, + "zerog": { "value": 10, "rank": "Trained" }, + "zoology": { "value": 10, "rank": "Trained" }, + "asteroidmining": { "value": 15, "rank": "Expert" }, + "ecology": { "value": 15, "rank": "Expert" }, + "explosives": { "value": 15, "rank": "Expert" }, + "fieldmedicine": { "value": 15, "rank": "Expert" }, + "firearms": { "value": 15, "rank": "Expert" }, + "hacking": { "value": 15, "rank": "Expert" }, + "handtohandcombat": { "value": 15, "rank": "Expert" }, + "mechanicalrepair": { "value": 15, "rank": "Expert" }, + "mysticism": { "value": 15, "rank": "Expert" }, + "pathology": { "value": 15, "rank": "Expert" }, + "pharmacology": { "value": 15, "rank": "Expert" }, + "physics": { "value": 15, "rank": "Expert" }, + "piloting": { "value": 15, "rank": "Expert" }, + "psychology": { "value": 15, "rank": "Expert" }, + "tactics": { "value": 15, "rank": "Expert" }, + "wildernesssurvival": { "value": 15, "rank": "Expert" }, + "artificialintenligence": { "value": 20, "rank": "Master" }, + "command": { "value": 20, "rank": "Master" }, + "cybernetics": { "value": 20, "rank": "Master" }, + "engineering": { "value": 20, "rank": "Master" }, + "exobiology": { "value": 20, "rank": "Master" }, + "hyperspace": { "value": 20, "rank": "Master" }, + "planetology": { "value": 20, "rank": "Master" }, + "robotics": { "value": 20, "rank": "Master" }, + "sophontology": { "value": 20, "rank": "Master" }, + "surgery": { "value": 20, "rank": "Master" }, + "xenoesoterism": { "value": 20, "rank": "Master" }, } let conditions = { @@ -232,269 +233,186 @@ let conditions = { async function createActorFromJson(jsonData) { let actorData; let newActor; - // if (actorData.armor.length) { - // newActor.system.stats.armor = { - // "value": actorData.armor.armorPoints, - // "label": Armor - // } - // } try { actorData = JSON.parse(jsonData); newActor = { - "name": actorData.name, - "type": "character", - "img": "icons/svg/mystery-man.svg", - "system": { - "health": { - "value": actorData.health, - "max": actorData.maxHealth, - "min": 0 - }, - "hits": { - "value": actorData.wounds, - "max": actorData.maxWounds - }, - "biography": "", - "notes": "", - "weight": {"current": 0, "capacity": 0}, - "settings": {"useCalm": false}, - "class": { - "value": actorData.characterClass.charAt(0).toUpperCase() + actorData.characterClass.slice(1) - }, - "rank": {"value": ""}, - "pronouns": {"value": actorData.pronouns}, - "credits": {"value": actorData.credits}, - "stressdesc": {"value": actorData.traumaResponse}, - "xp": { "value": 0, "html": 0, "selectedSkill": ""}, - "stressdesc": {"value": actorData.traumaResponse}, - "attributes": {"level": { "value": actorData.highScore }}, - "stats": { - "strength": { - "value": actorData.strength, - "label": "Strength", - "mod": null - }, - "speed": { - "value": actorData.speed, - "label": "Speed", - "mod": null - }, - "intellect": { - "value": actorData.intellect, - "label": "Intellect", - "mod": null - }, - "combat": { - "value": actorData.combat, - "label": "Combat", - "mod": null - }, - "sanity": { - "value": actorData.sanity, - "label": "Sanity" - }, - "fear": { - "value": actorData.fear, - "label": "Fear" - }, - "body": { - "value": actorData.body, - "label": "Body" - } - }, - "other": { - "stress": { - "value": actorData.stress, - "min": actorData.minStress, - "label": "Stress" - }, - "resolve": 0 - } - }, - "prototypeToken": { "name": actorData.name, - "displayName": 0, - "actorLink": false, - "texture": { - "src": "icons/svg/mystery-man.svg", - "scaleX": 1, - "scaleY": 1, - "offsetX": 0, - "offsetY": 0, - "rotation": 0, - "tint": null - }, - "width": 1, - "height": 1, - "lockRotation": false, - "rotation": 0, - "alpha": 1, - "disposition": -1, - "displayBars": 0, - "bar1": { - "attribute": "health" - }, - "bar2": { - "attribute": "power" - }, - "light": { - "alpha": 0.5, - "angle": 360, - "bright": 0, - "color": null, - "coloration": 1, - "dim": 0, - "attenuation": 0.5, - "luminosity": 0.5, - "saturation": 0, - "contrast": 0, - "shadows": 0, - "animation": { - "type": null, - "speed": 5, - "intensity": 5, - "reverse": false + "type": "character", + "img": "icons/svg/mystery-man.svg", + "system": { + "health": { + "value": actorData.health, + "max": actorData.maxHealth, + "min": 0 }, - "darkness": { - "min": 0, - "max": 1 + "hits": { + "value": actorData.wounds, + "max": actorData.maxWounds + }, + "biography": "", + "notes": "", + "weight": { "current": 0, "capacity": 0 }, + "settings": { "useCalm": false }, + "class": { + "value": actorData.characterClass.charAt(0).toUpperCase() + actorData.characterClass.slice(1) + }, + "rank": { "value": "" }, + "pronouns": { "value": actorData.pronouns }, + "credits": { "value": actorData.credits }, + "stressdesc": { "value": actorData.traumaResponse }, + "xp": { "value": 0, "html": 0, "selectedSkill": "" }, + "stressdesc": { "value": actorData.traumaResponse }, + "attributes": { "level": { "value": actorData.highScore } }, + "stats": { + "strength": { + "value": actorData.strength, "label": "Strength", "mod": null + }, + "speed": { + "value": actorData.speed, "label": "Speed", "mod": null + }, + "intellect": { + "value": actorData.intellect, "label": "Intellect", "mod": null + }, + "combat": { + "value": actorData.combat, "label": "Combat", "mod": null + }, + "sanity": { + "value": actorData.sanity, "label": "Sanity" + }, + "fear": { + "value": actorData.fear, "label": "Fear" + }, + "body": { + "value": actorData.body, "label": "Body" + } + }, + "other": { + "stress": { + "value": actorData.stress, "min": actorData.minStress, "label": "Stress" + }, + "resolve": 0 } - }, - "sight": { - "enabled": false, - "range": null, - "angle": 360, - "visionMode": "basic", - "color": null, - "attenuation": 0.1, - "brightness": 0, - "saturation": 0, - "contrast": 0 - }, - "detectionModes": [], - "flags": {}, - "randomImg": false + } + }; + var items = []; + if (actorData.trinket) { + items.push({ + "name": "Trinket: " + actorData.trinket, "type": "item" + }) } - }; - var items = []; - if (actorData.trinket) { - items.push({ - "name": "Trinket: " + actorData.trinket, - "type": "item" - }) - } - if (actorData.patch) { - items.push({ - "name": "Patch: " + actorData.patch, - "type": "item" - }) - } - // Equipment - for (let i = 0; i < actorData.equipment.length; i++) { - items.push({ - "name": actorData.equipment[i].name, - "type": "item", - "system": { - "description": actorData.equipment[i].description, - "cost": actorData.equipment[i].cost, - "quantity": actorData.equipment[i].quantity - }, - "img": "icons/svg/item-bag.svg", - }) - } - // Items - for (let i = 0; i < actorData.items.length; i++) { - items.push({ - "name": actorData.items[i].title, - "type": "item", - "system": { - "description": actorData.items[i].description, - "cost": actorData.items[i].cost, - "quantity": actorData.items[i].quantity - }, - "img": "icons/svg/item-bag.svg", - }) - } - // Armor - for (let i = 0; i < actorData.armor.length; i++) { - items.push({ - "name": actorData.armor[i].name, - "type": "armor", - "system": { - "description": actorData.armor[i].notes, - "cost": actorData.armor[i].cost, - "bonus": actorData.armor[i].armorPoints, - "equipped": actorData.armor[i].equipped - }, - "img": "icons/svg/item-bag.svg", - }) - } - // Weapons - for (let i = 0; i < actorData.weapons.length; i++) { - items.push({ - "name": actorData.weapons[i].weaponType, - "type": "weapon", - "system": { - "description": actorData.weapons[i].special, - "cost": actorData.weapons[i].cost, - "ranges": { - "short": 0, - "medium": 0, - "long": 0, - "value": actorData.weapons[i].weaponRange + if (actorData.patch) { + items.push({ + "name": "Patch: " + actorData.patch, "type": "item" + }) + } + // Equipment + for (let i = 0; i < actorData.equipment.length; i++) { + items.push({ + "name": actorData.equipment[i].name, + "type": "item", + "system": { + "description": actorData.equipment[i].description, + "cost": actorData.equipment[i].cost, + "quantity": actorData.equipment[i].quantity }, - "equipped": actorData.weapons[i].equipped, - "critEffect": actorData.weapons[i].critical, - "shots": actorData.weapons[i].shots, - "curShots": actorData.weapons[i].shots, - "ammo": actorData.weapons[i].magazines, - "shotsPerFire": "1", - "useAmmo": false, - "ammoType": "", - "critDmg": actorData.weapons[i].critical, - "critEffect": "", - "damage": actorData.weapons[i].damageString - }, - "img": "icons/svg/item-bag.svg", - }) - } - // Skills - for (let i = 0; i < actorData.skills.length; i++) { - let words = actorData.skills[i].split(/(?=[A-Z])/); - let skillName = words.map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' '); - items.push({ - "name": skillName, - "type": "skill", - "system": { - "description": "", - "bonus": skillValues[actorData.skills[i].toLowerCase()].value, - "rank": skillValues[actorData.skills[i].toLowerCase()].rank - }, - "img": "icons/svg/item-bag.svg", - }) - } - // Conditions - for (let i = 0; i < actorData.conditions.length; i++) { - let conName = actorData.conditions[i].conditionType; - let words = conName.split(/(?=[A-Z])/); - let name = words.map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' '); - if (actorData.characterClass == "android" && conName.toLowerCase() == "heartattack") { - name = "Short Circuit" + "img": "icons/svg/item-bag.svg", + }) } - items.push({ - "name": name, - "type": "condition", - "system": { - "description": conditions[conName.toLowerCase()], - "treatment": {"value": 0, "html": ""} - }, - "img": "icons/svg/item-bag.svg", - }) - } - newActor.items = items - - - } catch(err) { + // Items + for (let i = 0; i < actorData.items.length; i++) { + items.push({ + "name": actorData.items[i].title, + "type": "item", + "system": { + "description": actorData.items[i].description, + "cost": actorData.items[i].cost, + "quantity": actorData.items[i].quantity + }, + "img": "icons/svg/item-bag.svg", + }) + } + // Armor + for (let i = 0; i < actorData.armor.length; i++) { + items.push({ + "name": actorData.armor[i].name, + "type": "armor", + "system": { + "description": actorData.armor[i].notes, + "cost": actorData.armor[i].cost, + "bonus": actorData.armor[i].armorPoints, + "equipped": actorData.armor[i].equipped + }, + "img": "icons/svg/item-bag.svg", + }) + } + // Weapons + for (let i = 0; i < actorData.weapons.length; i++) { + items.push({ + "name": actorData.weapons[i].weaponType, + "type": "weapon", + "system": { + "description": actorData.weapons[i].special, + "cost": actorData.weapons[i].cost, + "ranges": { + "short": 0, + "medium": 0, + "long": 0, + "value": actorData.weapons[i].weaponRange + }, + "equipped": actorData.weapons[i].equipped, + "critEffect": actorData.weapons[i].critical, + "shots": actorData.weapons[i].shots, + "curShots": actorData.weapons[i].shots, + "ammo": actorData.weapons[i].magazines, + "shotsPerFire": "1", + "useAmmo": false, + "ammoType": "", + "critDmg": actorData.weapons[i].critical, + "critEffect": "", + "damage": actorData.weapons[i].damageString + }, + "img": "icons/svg/item-bag.svg", + }) + } + // Skills + for (let i = 0; i < actorData.skills.length; i++) { + // Really betting for the app to only export base skills, if in the future + // they add custom skills, they'll need to be checked if they even exist + let words = actorData.skills[i].split(/(?=[A-Z])/); + let skillName = words.map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' '); + items.push({ + "name": skillName, + "type": "skill", + "system": { + "description": "", + "bonus": skillValues[actorData.skills[i].toLowerCase()].value, + "rank": skillValues[actorData.skills[i].toLowerCase()].rank + }, + "img": "icons/svg/item-bag.svg", + }) + } + // Conditions + for (let i = 0; i < actorData.conditions.length; i++) { + // Same thing as skills + let conName = actorData.conditions[i].conditionType; + let words = conName.split(/(?=[A-Z])/); + let name = words.map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' '); + //-Minor consideration since the app eports heartAttack for both + if (actorData.characterClass == "android" && conName.toLowerCase() == "heartattack") { + name = "Short Circuit" + } + items.push({ + "name": name, + "type": "condition", + "system": { + "description": conditions[conName.toLowerCase()], + "treatment": { "value": 0, "html": "" } + }, + "img": "icons/svg/item-bag.svg", + }) + } + newActor.items = items + } catch (err) { console.error(err); ui.notifications.error("Invalid JSON data"); return; @@ -509,7 +427,7 @@ async function createActorFromJson(jsonData) { try { await Actor.create(newActor); ui.notifications.info("Actor created successfully"); - } catch(err) { + } catch (err) { console.error(err); ui.notifications.error("Failed to create actor"); } From 94f54dca5c08ef508fa2fcc2b4331c0b3d19d4a7 Mon Sep 17 00:00:00 2001 From: Abraham Nassiff Date: Sun, 4 Jun 2023 12:17:43 -0500 Subject: [PATCH 3/3] Switched text input to file upload, improved some messages --- module/mosh.js | 52 +++++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/module/mosh.js b/module/mosh.js index eb9a60b..533cc6f 100644 --- a/module/mosh.js +++ b/module/mosh.js @@ -155,8 +155,6 @@ async function createMothershipMacro(data, slot) { return false; } - - /* -------------------------------------------- */ /* Actor from JSON */ /* -------------------------------------------- */ @@ -414,7 +412,7 @@ async function createActorFromJson(jsonData) { newActor.items = items } catch (err) { console.error(err); - ui.notifications.error("Invalid JSON data"); + ui.notifications.error("Invalid JSON, make sure you exported it from the Mothership Companion App"); return; } @@ -426,32 +424,46 @@ async function createActorFromJson(jsonData) { try { await Actor.create(newActor); - ui.notifications.info("Actor created successfully"); + ui.notifications.info("Character imported successfully!"); } catch (err) { console.error(err); - ui.notifications.error("Failed to create actor"); + ui.notifications.error("Failed to import character, check console for more details."); } } let d = new Dialog({ - title: "Create Actor from JSON", - content: `

Paste your JSON data below:

`, + title: "Mothership Companion JSON Import", + content: ` +
+
+ + +
+
+ `, buttons: { - save: { - icon: '', - label: "Create", - callback: (html) => { - const jsonData = html.find('#json-data').val(); - createActorFromJson(jsonData); + upload: { + label: "Upload", + callback: (html) => { + let fileInput = html.find('#json-upload')[0]; + let file = fileInput.files[0]; + let reader = new FileReader(); + + reader.onload = (event) => { + let contents = event.target.result; + createActorFromJson(contents); + }; + + reader.onerror = (event) => { + console.error(`File could not be read: ${event.target.error}`); + }; + + reader.readAsText(file); + } } - }, - cancel: { - icon: '', - label: "Cancel" - } }, - default: "save" -}); + default: "upload" +}) d.render(true);