Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

D&D 4e Character & Monster Importers

I'm still playing 4e, and now that HoneyBadger released the really cool new PowerCards 2.0 script, I've been spending my evenings manually updating every powercard for all characters and monsters in my campaigns. Is there any possibility of updating the 4e Character and Monster Import scripts to bring in the attributes and powers using the new tags and enhancements? Is this still an active project? I rolled an 8 for my Javascript skill, and really really appreciate all the work you guys have invested into this. Thank you!
...it still works with the older PowerCards version (the importer). I'm sure he'll update it eventually for the new PowerCards (at least, I hope he does...some of the new features are neat).
i'm currently updating honey-badger scripts for character import and monster import to use with the 4e sheet and the new power cards, i just need some time to handle the inventory thing ... and the power options offered by the sheet (like how to create the repeatable sections which is my todo for tonight)
Cool! Thank you!
1424687912

Edited 1424687964
Hello, here is a first draft, be advised that it don't make security checks for the character existance nor fill all the sheet. at the moment it only fill the 6 main attributes, create powercards and associated macros, it also add the trained skills (via the checkbox) it still a WIP version and it's quite far from being released (but i'm on vacation this week so it'll evolve fast i think.) And of course it's mainly HoneyBadger's Work so Kudos to him var AddPCAttribute = AddPCAttribute || {}; var AddPCPower = AddPCPower || {}; var AddPCPowerMacro = AddPCPowerMacro || {}; on("chat:message", function(msg) { // Exit if not an api command if (msg.type != "api") return; // Get the API Chat Command msg.who = msg.who.replace(" (GM)", ""); msg.content = msg.content.replace("(GM) ", ""); var command = msg.content.split(" ", 1); if (command == "!build-character") { if (!msg.selected) return; var n = msg.content.split(" ", 2); var Token = getObj("graphic", n[1]) if (Token.get("subtype") != "token") return; if (Token.get("gmnotes").indexOf("D20Character") == -1) return; // USER CONFIGURATION var USE_POWER_CARDS = true; // REPLACE SPECIAL CHARACTERS StatBlock = StatBlock.replace(//g, ""); var StatBlock = Token.get("gmnotes"); StatBlock = StatBlock.replace(/%20/g, " "); // Replace %20 with a space StatBlock = StatBlock.replace(/%21/g, "!"); // Replace %21 with a ! StatBlock = StatBlock.replace(/%22/g, "'"); // Replace %22 (quotation) with ' StatBlock = StatBlock.replace(/%26amp/g, "&"); // Replace %26amp (ampersand) with & StatBlock = StatBlock.replace(/%26apos/g, "'"); // Replace %26apos with ' StatBlock = StatBlock.replace(/%26lt/g, "<"); // Replace %26lt with < StatBlock = StatBlock.replace(/%26gt/g, ">"); // Replace %26gt with > StatBlock = StatBlock.replace(/%27/g, "'"); // Replace %27 with ' StatBlock = StatBlock.replace(/%28/g, "("); // Replace %28 with ( StatBlock = StatBlock.replace(/%29/g, ")"); // Replace %29 with ) StatBlock = StatBlock.replace(/%2C/g, ","); // Replace %2C with , StatBlock = StatBlock.replace(/%3A/g, ":"); // Replace %3A with : StatBlock = StatBlock.replace(/%3B/g, ""); // Remove %3B (semi-colon) StatBlock = StatBlock.replace(/%3Cbr/g, ""); // Remove carriage returns StatBlock = StatBlock.replace(/%3D/g, "="); // Replace %3D with = StatBlock = StatBlock.replace(/%3E/g, ""); // Remove %3E (???) StatBlock = StatBlock.replace(/%3F/g, "?"); // Replace %3F with ? StatBlock = StatBlock.replace(/\s{2,}/g, " "); // Replace multiple spaces with one space StatBlock = StatBlock.replace(/%u2013/g, "-"); // Replace %u2013 with - StatBlock = StatBlock.replace(/%u2019/g, "'"); // Replace %u2019 with ' // END SPECIAL CHARACTER REPLACEMENT or REMOVAL // GET NAME OF CHARACTER var CharacterName = StatBlock.match(/<name>(.*?)<\/name>/g)[0].split(">")[1].split("<", 1)[0].trim(); // CHECK FOR DUPLICATE CHARACTERS var CheckSheet = findObjs({ _type: "character", name: CharacterName }); // CREATE CHARACTER SHEET & LINK TOKEN TO SHEET var Character = createObj("character", { name: CharacterName, gmnotes: Token.get("gmnotes"), archived: false }); // CHARACTER LEVEL var Level = parseInt(StatBlock.match(/<Level>(.*?)<\/Level>/g)[0].match(/\d+/g)[0]); // ABILITY SCORE MODS, SKILLS, HP, & MORE var Stats = StatBlock.match(/<Stat value=(.*?)\/>/g); log (Stats); var Skills = {}; var SkillTraining = {}; var s = 0; while (s < Stats.length) { // ABILITY SCORE if (Stats[s].indexOf("'Constitution'") != -1) var CONValue = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Strength'") != -1) var STRValue = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Dexterity'") != -1) var DEXValue = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Intelligence'") != -1) var INTValue = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Wisdom'") != -1) var WISValue = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Charisma'") != -1) var CHAValue = parseInt(Stats[s].match(/\d+/g)[0]); // HIT POINTS & SURGES if (Stats[s].indexOf("'Hit Points'") != -1) var HitPoints = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Healing Surges'") != -1) var HealingSurges = parseInt(Stats[s].match(/\d+/g)[0]); // SKILLS if (Stats[s].indexOf("'Acrobatics'") != -1) Skills["acrobatics"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Arcana'") != -1) Skills["arcana"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Athletics'") != -1) Skills["athletics"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Bluff'") != -1) Skills["bluff"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Diplomacy'") != -1) Skills["diplomacy"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Dungeoneering'") != -1) Skills["dungeoneering"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Endurance'") != -1) Skills["endurance"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'History'") != -1) Skills["history"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Heal'") != -1) Skills["heal"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Insight'") != -1) Skills["insight"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Intimidate'") != -1) Skills["intimidate"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Nature'") != -1) Skills["nature"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Perception'") != -1) Skills["perception"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Religion'") != -1) Skills["religion"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Stealth'") != -1) Skills["stealth"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Streetwise'") != -1) Skills["streetwise"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Thievery'") != -1) Skills["thievery"] = parseInt(Stats[s].match(/\d+/g)[0]); // SKILL TRAINING if (Stats[s].indexOf("'Acrobatics Trained'") != -1) SkillTraining["acrobatics"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Arcana Trained'") != -1) SkillTraining["arcana"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Athletics Trained'") != -1) SkillTraining["athletics"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Bluff Trained'") != -1) SkillTraining["bluff"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Diplomacy Trained'") != -1) SkillTraining["diplomacy"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Dungeoneering Trained'") != -1) SkillTraining["dungeoneering"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Endurance Trained'") != -1) SkillTraining["endurance"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'History Trained'") != -1) SkillTraining["history"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Heal Trained'") != -1) SkillTraining["heal"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Insight Trained'") != -1) SkillTraining["insight"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Intimidate Trained'") != -1) SkillTraining["intimidate"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Nature Trained'") != -1) SkillTraining["nature"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Perception Trained'") != -1) SkillTraining["perception"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Religion Trained'") != -1) SkillTraining["religion"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Stealth Trained'") != -1) SkillTraining["stealth"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Streetwise Trained'") != -1) SkillTraining["streetwise"] = parseInt(Stats[s].match(/\d+/g)[0]); if (Stats[s].indexOf("'Thievery Trained'") != -1) SkillTraining["thievery"] = parseInt(Stats[s].match(/\d+/g)[0]); // SPEED if (Stats[s].indexOf("'Speed'") != -1) var Speed = parseInt(Stats[s].match(/\d+/g)[0]); s++; } // ADD ATTRIBUTES TO SHEET (Non-character sheet version) AddPCAttribute("level", Level, Character.id); var HitPointsID = AddPCAttribute("hp", HitPoints, Character.id).id; var SurgesID = AddPCAttribute("surges", HealingSurges, Character.id).id; AddPCAttribute("surge-value", Math.floor(HitPoints/4), Character.id); AddPCAttribute("strength", STRValue, Character.id); AddPCAttribute("constitution", CONValue, Character.id); AddPCAttribute("dexterity", DEXValue, Character.id); AddPCAttribute("intelligence", INTValue, Character.id); AddPCAttribute("wisdom", WISValue, Character.id); AddPCAttribute("charisma", CHAValue, Character.id); AddPCAttribute("speed", Speed, Character.id); // SET TOKEN SETTINGS Token.set("represents", Character.id); Token.set("name", CharacterName); Token.set("showplayers_name", true); Token.set("bar2_link", SurgesID); Token.set("bar3_link", HitPointsID); Token.set("showplayers_bar3", true); Token.set("aura2_radius", "0"); Token.set("aura2_color", "#14A70A"); Token.set("aura2_square", true); var SkillList = ["acrobatics", "arcana", "athletics", "bluff", "diplomacy", "dungeoneering", "endurance", "heal", "history", "insight", "intimidate", "nature", "perception", "religion", "stealth", "streetwise", "thievery"]; var s = 0; while (s < SkillList.length) { if (SkillTraining[SkillList[s]] !=0) AddPCAttribute(SkillList[s]+ "-trained",1,Character.id); s++ } AddPCPowerMacro("█▓▒░POWERS░▒▓█", "", Character.id, true); var PowersBlock = StatBlock.match(/<Power name=(.*?)<\/Power>/g); var p = 0; while (p < PowersBlock.length) { // DEFINE VARIABLES var Power = {}; var Key = ""; var Content = ""; var PowerName = PowersBlock[p].match(/<Power name='(.*?)' >/g)[0].split("='")[1].split("' ")[0]; var AtkBonus = (PowersBlock[p].match(/<AttackBonus>(.*?)<\/AttackBonus>/g) != null) ? PowersBlock[p].match(/<AttackBonus>(.*?)<\/AttackBonus>/g)[0].match(/\d+/g)[0] : "0"; var DmgRoll = (PowersBlock[p].match(/<Damage>(.*?)<\/Damage>/g) != null) ? PowersBlock[p].match(/<Damage>(.*?)<\/Damage>/g)[0].split(">")[1].split("</")[0] : ""; var DmgType = (PowersBlock[p].match(/<DamageType>(.*?)<\/DamageType>/g) != null) ? PowersBlock[p].match(/<DamageType>(.*?)<\/DamageType>/g)[0].split(">")[1].split("</")[0] : ""; // REMOVE EMPTY ENTRIES TO PREVENT ERRORS PowersBlock[p] = PowersBlock[p].replace("<specific name='Keywords' />", ""); PowersBlock[p] = PowersBlock[p].replace("<specific name='Keywords'/>", ""); PowersBlock[p] = PowersBlock[p].replace("<specific name='Level' />", ""); PowersBlock[p] = PowersBlock[p].replace("<specific name='Level'/>", ""); PowersBlock[p] = PowersBlock[p].replace("<specific name='Attack Type' />", ""); PowersBlock[p] = PowersBlock[p].replace("<specific name='Attack Type'/>", ""); PowersBlock[p] = PowersBlock[p].replace("<table>", ""); PowersBlock[p] = PowersBlock[p].replace("</table>", ""); // PARSE POWER INFORMATION var PowerInfo = PowersBlock[p].match(/<specific name=(.*?)<\/specific>/g); var i = 0; var HitCount = 1; while (i < PowerInfo.length) { Key = PowerInfo[i].match(/='(.*?)' >/g)[0].split("='")[1].split("' >")[0]; Content = PowerInfo[i].split(" > ")[1].split(" </")[0].split("Level")[0]; // CHECK FOR DUPLICATE HIT ENTRIES - MOST OFTEN FOUND ON POWERS // WITH SECONDARY/TERTIARY TARGETS &/OR ATTACKS if (Key == "Hit" && Power["Hit"] != undefined) { HitCount++; Key = "Hit" + HitCount; } Power[Key] = Content; i++; } // CHECK FOR MULTIPLE ATTACK POWERS var MultiAttack = ""; if (Power["Target"] != undefined) { switch (Power["Target"]) { case "One ally": case "One creature": case "One enemy": case "Same as primary target": case "The triggering ally": case "The triggering creature": case "The triggering enemy": case "The triggering ally in the burst": case "The triggering creature in the burst": case "The triggering enemy in the burst": case "One ally adjacent to you": case "One creature adjacent to you": case "One enemy adjacent to you": MultiAttack = ""; break; default: MultiAttack = "?{Number of Targets|1}"; } } var c = p+1 // BUILD POWERSTRING PowerString = "!power --name|@{power-" + c + "-name}"; PowerString += (Power["Display"] != undefined) ? " --title|" + Power["Display"] : ""; PowerString += (Power["Power Usage"] != undefined) ? " --format|@{power-" + c + "-useage} --leftsub|" + Power["Power Usage"] : ""; PowerString += (Power["Action Type"] != undefined) ? " --rightsub|" + Power["Action Type"] : ""; PowerString += (Power["Flavor"] != undefined) ? " --emote|" + Power["Flavor"] : ""; PowerString += (Power["Attack Type"] != undefined) ? " --Range|" + Power["Attack Type"] : ""; PowerString += (Power["Trigger"] != undefined) ? " --Trigger|" + Power["Trigger"] : ""; PowerString += (Power["Requirement"] != undefined) ? " --Requirement|" + Power["Requirement"] : ""; PowerString += (Power["Target"] != undefined) ? " --Target(s)|" + Power["Target"] : ""; PowerString += (Power["Attack"] != undefined) ? " --attack" + MultiAttack + "|[[1d20 + " + AtkBonus + "]]" : ""; PowerString += (Power["Attack"] != undefined) ? " --defense|" + Power["Attack"].split("vs.")[1] : ""; PowerString += (Power["Primary Target"] != undefined) ? " --Primary Target|" + Power["Primary Target"] : ""; PowerString += (Power["Primary Attack"] != undefined) ? " --Primary Attack|[[1d20 + " + AtkBonus + "]] vs " + Power["Primary Attack"].split("vs.")[1] : ""; PowerString += (Power["Hit"] != undefined && isNaN(Power["Hit"].charAt(0)) == true) ? " --On Hit|" + Power["Hit"] : ""; PowerString += (Power["Hit"] != undefined && isNaN(Power["Hit"].charAt(0)) == false) ? " --damage|[[" + DmgRoll + "]] " + DmgType.toLowerCase() + " " + Power["Hit"].substring(Power["Hit"].indexOf("damage")) : ""; PowerString += (Power["Secondary Target"] != undefined) ? " --^Secondary Target|" + Power["Secondary Target"] : ""; PowerString += (Power["Secondary Attack"] != undefined) ? " --^Secondary Attack|[[1d20 + " + AtkBonus + "]] vs " + Power["Secondary Attack"].split("vs.")[1] : ""; PowerString += (Power["Hit2"] != undefined && isNaN(Power["Hit2"].charAt(0)) == true) ? " --^Secondary Hit|" + Power["Hit2"] : ""; PowerString += (Power["Hit2"] != undefined && isNaN(Power["Hit2"].charAt(0)) == false) ? " --^Secondary Hit|[[" + DmgRoll + "]] " + DmgType.toLowerCase() + " " + Power["Hit2"].substring(Power["Hit2"].indexOf("damage")) : ""; PowerString += (Power["Tertiary Target"] != undefined) ? " --^2Tertiary Target|" + Power["Tertiary Target"] : ""; PowerString += (Power["Tertiary Attack"] != undefined) ? " --^2Tertiary Attack|[[1d20 + " + AtkBonus + "]] vs " + Power["Tertiary Attack"].split("vs.")[1] : ""; PowerString += (Power["Hit3"] != undefined && isNaN(Power["Hit3"].charAt(0)) == true) ? " --^2Tertiary Hit|" + Power["Hit3"] : ""; PowerString += (Power["Hit3"] != undefined && isNaN(Power["Hit3"].charAt(0)) == false) ? " --^2Tertiary Hit|[[" + DmgRoll + "]] " + DmgType.toLowerCase() + " " + Power["Hit3"].substring(Power["Hit3"].indexOf("damage")) : ""; PowerString += (Power["Miss"] != undefined) ? " --Miss|" + Power["Miss"] : ""; PowerString += (Power["Effect"] != undefined) ? " --Effect|" + Power["Effect"] : ""; PowerString += (Power[""] != undefined) ? " --Range|" + Power[""] : ""; AddPCPowerMacro(PowerName, "@{power-" + c + "-macro}", CheckSheet.id, true, p); AddPCPower("power-" + c + "-name", PowerName, CheckSheet.id); AddPCPower("power-" + c + "-useage", Power["Power Usage"], CheckSheet.id); AddPCPower("power-" + c + "-macro", PowerString, CheckSheet.id); AddPCPower("power-" + c + "-toggle", "on", CheckSheet.id); p++; } } }); function AddPCAttribute (attr, value, charid) { var attrid = ""; if (attr === "hp") { attrid = createObj("attribute", { name: attr, current: value, max: value, characterid: charid }); } else { attrid = createObj("attribute", { name: attr, current: value, characterid: charid }); } return attrid; } function AddPCPowerMacro (powername, powerstring, charid, tokenaction) { createObj("ability", { name: powername, description: "", action: powerstring, istokenaction: tokenaction, characterid: charid }); } function AddPCPower (attr, value, charid) { var attrid = ""; attrid = createObj("attribute", { name: attr, current: value, characterid: charid }); return attrid; }