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

[Script] PF Character Sheet - Hero Lab character importer

March 14 (9 years ago)

Edited March 17 (9 years ago)
James W.
Sheet Author
API Scripter
Since the only script for importing Hero Lab characters hasn't been updated in over a year (not to mention the link to it is dead), I've been working on my own script to import characters into the Pathfinder character sheet. I should mention that due to the API environment not including the XML DOM parsing part of the JavaScript language, I've opted to convert the XML to JSON first, rather than trying to hack together a way to process the XML as text.

Usage:
  1. Export the character (or characters) as an XML file in Hero Lab (File -> Save Custom Output, choose "Generate XML File").
  2. Open the XML file in your favorite text editor that isn't WordPad, MS Word, or any other word processor (I recommend Notepad++) and copy the entire contents (Ctrl-A, then Ctrl-C, for the shortcut-impaired).
  3. Go to CodeBeautify.org's XML to JSON converter, and convert the XML to JSON (paste the XML into the field on the left, set the result mode to "text", click "XML to JSON", then copy the text from the text field on the right).
  4. Paste the JSON text into the GM Notes on a token you intend to use for the FIRST character in the XML file (if you're importing more than one).
  5. Repeat steps 1-4 on new tokens, if you want to import multiple files at once.
  6. Select the token (or tokens), type "!hl-import" into the chat window, and press enter.
What the script (currently) does:
The script will look for a character object with the same name as the character it's importing from Hero Lab; if it finds one, it'll import to that character, otherwise it will create a new character with that name.  It will do this for all of the characters in the import, including any "minions" attached to a character, such as familiars and animal companions; the first character in each XML file will be set to "represent" with the token used for the import.

The script currently imports the following:
  • Name (obviously)
  • Ability scores
  • Feats
  • Traits
  • Classes, including levels
  • Current XP
  • Favored class (only if manually set, and only the name)
  • BAB
  • Skills (situational modifiers get added to the macro as new template lines)
  • Saving throws
  • Max Dex Bonus
  • Armor Check Penalty
  • Arcane Spell Failure
  • Hit dice (HD > class levels, it gets dumped into the level for class #5)
  • Spell caster classes
  • Spells (from currently memorized, known, and spellbook)
  • Size
  • Languages
  • DR
  • Resistances
  • Immunities
  • Weaknesses
  • Senses (low-light, darkvision, scent, etc)
  • Challenge Rating
  • XP award (what the character's CR is worth)
  • Personal details, including: player name, deity, race, alignment, gender, age, height, weight, hair, eye, and skin color
Currently NOT imported:
  • Class features
  • Racial traits
  • AC
  • Items
  • Attacks
  • Flaws
  • Type/subtypes
  • Hero points
  • Token sight properties (eventually it will automatically set darkvision/low-light vision)
  • Undoubtedly a bunch of stuff I've forgotten
Known issues (some are script issues, some are character sheet issues):
  • You'll almost certainly need to manually recalc the character after importing
  • Spellclasses will be set to the appropriate class from the Classes tab, but it won't populate the "name", and it won't populate the caster level until you manually change the class' level on the Classes tab (not even a recalc will fix this).
  • Since it isn't actually specified in the XML, the script will make its best guess as to which ability score a spellclass uses (but only if it hasn't already been set).
  • Bonus spells don't seem to populate until you change the ability mod it uses to something else and back again.
Other notes:
  • Importing feats will attempt to find an existing feat on the sheet with the same name; if found, it'll overwrite that feat, instead of making a new one
  • If it finds multiple feats with the same name, it will append how many times you've taken it at the end of the name; this does not effect feats that have you select weapons (since the weapon name is listed as part of the feat name), but will apply to feats like Extra Rogue Talent.
  • Likewise, importing spells will attempt to find a spell with the same name, level, and spellclass.
  • Importing class features, racial traits, and items will work the same way (once they're added), so you should be able to re-import over existing characters with minimal duplication.
  • Stats like HP, base save bonuses, BAB, etc., aren't listed per-class in the XML, so the script will dump it all into the first class on the sheet.
  • Before importing skills, the script will delete all skill-related attributes; this includes any changes to skill macros.  If you have custom skill macros you wish to keep, back them up first.
  • Currently the script won't clear the GM notes on the token, but future versions will.  The characters I'm testing this with end up being thousands of lines of JSON, which causes a bit of lag when opening the token's properties.  There will be a debug mode that disables this.
Please post any constructive comments or bug reports here!
Good luck, glad someone has taken this one on.  It's a challenging project due to differences between the Roll20 sheet and the HL's very limited XML output.
March 17 (9 years ago)
Recieved the following error while attempting to import Jaagrath Kreeg from the Hero Labs Rise of the Runelords Encounter Library.

Your scripts are currently disabled due to an error that was detected. Please make appropriate changes to your scripts and click the "Save Script" button and we'll attempt to start running them again. More info...
For reference, the error message generated was: /home/symbly/www/d20-api-server/node_modules/firebase/lib/firebase-node.js:1 orts, require, module, __filename, __dirname) { function g(a){throw a;}var j=v ^ TypeError: Cannot read property 'length' of undefined at importSpellClasses (evalmachine.<anonymous>:5667:31) at importCharacter (evalmachine.<anonymous>:5817:19) at evalmachine.<anonymous>:5956:7 at Array.forEach (native) at evalmachine.<anonymous>:5954:16 at Function._.each._.forEach (/home/symbly/www/d20-api-server/sandcastle/node_modules/underscore/underscore.js:153:9) at HandleInput (evalmachine.<anonymous>:5950:6) at eval (
March 17 (9 years ago)
James W.
Sheet Author
API Scripter
I don't have that HeroLabs package, so I can't really do too much debugging on that unless you provide me an XML file to work with.

That said, that error message will probably be enough for me to track down the issue, so I'll take a look at it after work.
March 17 (9 years ago)
James W.
Sheet Author
API Scripter
Alright, looked it over, and I've made an update that should fix that error; go ahead and pull the latest version from the link in the OP.
March 18 (9 years ago)

Edited March 18 (9 years ago)
chris b.
Pro
Sheet Author
API Scripter
Combat Manager can import hero lab files, i think it is open source, so it might have some hints there.

(the spellclass level not updating is fixed in dev, and should be in beta and then prod soon)

March 18 (9 years ago)
James W.
Sheet Author
API Scripter
Between being fairly experienced in dealing with XML files, and Combat Manager dealing with the data in a way that's completely different than the Roll20 character sheet, I don't think looking at that code will help too much.

That said, Combat Manager encounter files are already on my radar as far as other sources of imported data.
March 18 (9 years ago)
Issue fixed.

HL-Import:Jaagrath Kreeg import complete!
March 18 (9 years ago)
Recieved another error attempting to import Lucretia from the Hero Labs Rise of the Runelords Encounter Library.

below is the generated error message.

Your scripts are currently disabled due to an error that was detected. Please make appropriate changes to your scripts and click the "Save Script" button and we'll attempt to start running them again. More info...
For reference, the error message generated was: /home/symbly/www/d20-api-server/node_modules/firebase/lib/firebase-node.js:1 orts, require, module, __filename, __dirname) { function g(a){throw a;}var j=v ^ TypeError: Cannot read property 'public' of undefined at evalmachine.<anonymous>:5957:59 at Function._.each._.forEach (/home/symbly/www/d20-api-server/sandcastle/node_modules/underscore/underscore.js:153:9) at HandleInput (evalmachine.<anonymous>:5954:6) at eval (

I can get you the XML code if you need it.
March 18 (9 years ago)
James W.
Sheet Author
API Scripter
Yeah, I'm probably going to need the XML for that one.
March 30 (9 years ago)

Edited March 30 (9 years ago)
Just tried it tonight on Hero Lab Pathfinder Basic Cleric; works as described. I like it- keep up the good work! I would offer to help, but just getting my head around roll20, api, etc..
This is interesting.  Could you post an example output of the JSON file after it goes through the converter?  I currently have an API script that does PCGen importing by using a custom output sheet (just outputs variable/value pairs).  Given an example I could probably create one that emulates what comes out of Hero Lab so your script could be compatible with PCGen as well if you're interested.
April 12 (9 years ago)
James W.
Sheet Author
API Scripter
While that would certainly be nice of you, the JSON ends up being thousands of lines, and the data is less than complete (doesn't break things like base save or attack bonuses down per-class, for example), so I'm not terribly certain that would be the best of ideas; PCGen users might be better served with a separate API script.
Fair enough, I didn't realize it would end up being that long (never used HL).  The PCGen output ends up being pretty long as well, but in a way that's easy to loop through in the generation templates.  I'll probably just end up updating my own script and pushing it to the repository.
I have tried and the only thing I can seem to import is the ability scores.  I have followed the directions on two different test games and I got the same result. I am trying to import a pathfinder Goblin player character. The character sheet will show up with the name but the actual sheet has nothing but the ability scores. I don't even see any micros populate under abilities. I made sure Hero lab and Pathfinder were up to date. 
The script crashed.


Your scripts are currently disabled due to an error that was detected. Please make appropriate changes to your scripts and click the "Save Script" button and we'll attempt to start running them again. More info...
For reference, the error message generated was: TypeError: Cannot assign to read only property 'spellclass' of TypeError: Cannot assign to read only property 'spellclass' of at importCharacter (apiscript.js:5711:41) at apiscript.js:5855:7 at Array.forEach (native) at apiscript.js:5853:16 at Function._.each._.forEach (/home/node/d20-api-server/node_modules/underscore/underscore.js:153:9) at HandleInput (apiscript.js:5849:6) at eval (eval at <anonymous> (/home/node/d20-api-server/api.js:105:34), <anonymous>:65:16) at Object.publish (eval at <anonymous> (/home/node/d20-api-server/api.js:105:34), <anonymous>:70:8) at /home/node/d20-api-server/api.js:1197:12 at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:560
@James W.  Hi!  I see that you're using Hero Lab's "Save Custom Output" option, then running it through an XML-to-JSON converter.  An interesting thing about the .por files that Hero Lab generates is that they're not a super-sekrit proprietary format.  They're just a ZIP file that has a POR extension.

So if you take a .por file and rename it as a .zip, you can take a look at the actual contents of the file.  Like this:



The three "statblocks_" folders contain files for each hero in the portfolio, in the promised formats (HTML, plain text, XML).  The "herolab" folder contains internal data which is probably of little interest to you.

Theoretically, you could use a JavaScript-based ZIP library (like JSZip) to work directly with .por files, thus saving all the tedious preparatory steps.  With just a little extra processing built-in, you could even do batch import.  The index.xml file in the root contains a listing of the characters contained in the file, paths to the statblocks in all three formats, and so on.

I don't know if it'd be helpful, but the program hl2mt does exactly that.  It's written in Python rather than JS, and the output is meant for Maptool, but perhaps you might find the import routines useful.  The original source repository seems to have  moved to bitbucket, plus I have a copy of the source code that I'd be happy to share if you're interested.

Hope this helps.
script is crashing after running thought all the wonderful instructions.  I get the following. 

SyntaxError: Unexpected token & SyntaxError: Unexpected token & at Object.parse (native) at apiscript.js:825:33 at
Function._.each._.forEach (/home/node/d20-api-server/node_modules/underscore/underscore.js:153:9) at HandleInput
(apiscript.js:822:6) at eval (eval at <anonymous> (/home/node/d20-api-server/api.js:105:34), <anonymous>:65:16) at
Object.publish (eval at <anonymous> (/home/node/d20-api-server/api.js:105:34), <anonymous>:70:8) at
/home/node/d20-api-server/api.js:1197:12 at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:560
at hc (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:39:147) at Kd
(/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:546)

Disregard my last post i forgot to change the json converter to use text mode.   I was able to  import my character. I hope the
things that aren't currently imported will be able to be added in.  I love this script so far.