• Please note: In an effort to ensure that all of our users feel welcome on our forums, we’ve updated our forum rules. You can review the updated rules here: http://forums.wolflair.com/showthread.php?t=5528.

    If a fellow Community member is not following the forum rules, please report the post by clicking the Report button (the red yield sign on the left) located on every post. This will notify the moderators directly. If you have any questions about these new rules, please contact support@wolflair.com.

    - The Lone Wolf Development Team

Hero Lab scripting 201: Location, Location, Location

Mathias

Moderator
Staff member
This article is part of a collection of editor and scripting articles: http://forums.wolflair.com/showthread.php?t=21688

I decided to add an article on a topic I don't think we've covered in much detail anywhere else. The principles I'm discussing apply to all game systems in Hero Lab, but for this article I'll be drawing my examples from Pathfinder.

In a character in Hero Lab, there are many items - each attribute is an item, each feat, level of a class, archetype, weapon, etc. is its own individual item. For the rest of this article, I'll refer to them as picks.

Very often, while writing a script, you'll want to look up information on another pick (perhaps to set the number of uses equal to an attribute modifier), or you'll want to change something about another pick (like adding a bonus to a skill). I'll be discussing how to travel around the set of picks that make up your character and the sorts of things you can do once you get somewhere and that sorts of questions you can ask once you get there.

In Hero Lab's scripting language, the period: . is used as the transition from one place to another. You are allowed to make more that one transition in a row - it's actually very common to use many transitions in a row in order to travel from one pick to another.

Every pick in a Hero Lab character is stored within a container. 98% of the picks in a character will be in a container called "hero", and there's only one "hero" container for each character. The rest will be in containers called gizmos - those are containers that exist within other picks. Each pick can only have one gizmo, and most picks will not actually have a gizmo. Gizmos are used in cases where at item is customizable - the custom versions of armor, weapons, scrolls, potions, wands, spells, and wordspells.

Although I'm using the term container here, that isn't actually related to what you'd commonly call a container - things like backpacks and houses. If you tell Hero Lab that the group of alchemist's fire bottles you own should be stored within your belt pouch, it doesn't change the underlying container for either the alchemist's fire or the belt pouch. What it does do is to set up a new relationship between the alchemist's fire and the belt pouch. Within the scripting language, that relationship is referred to as gearholding, and I'll cover that later in this article.


Let's take a look at some transitions:

hero.child[skClimb].field[Bonus].value

Breaking that down:

hero
.
child[skClimb]
.
field[Bonus]
.
value

So, what that's saying is: first, travel to the hero, then travel to the child of the hero whose Id is "skClimb" (which is the climb skill), then travel to the field on that child whose Id is "Bonus" (which is for untyped bonuses), then report the value of that field.

Here's how you might use that:

Code:
hero.child[skClimb].field[Bonus].value = hero.child[skClimb].field[Bonus].value + 2

Or in other words: "set the untyped bonus of our climb skill equal to whatever bonus has already been applied, + 2". Or, "You get +2 to climb."

That one's actually so commonly used that we've added some abbreviations, so that it takes less typing to get the same effect:

Code:
#skillbonus[skClimb] += 2

Example #2:
hero.child[skClimb].tagis[Helper.ClassSkill]

hero
.
child[skClimb]
.
tagis[Helper.ClassSkill]

In other words: "travel to the hero container, and then to the climb skill pick that's in that container, and then report whether a Tag whose Id is "Helper.ClassSkill" is present on that pick". In simpler terms: "Is climb a class skill right now?"

tagis[], like all the other TRUE/FALSE questions in Hero Lab, will report it's answer in the form of a number. It will report "0" if the answer is FALSE, and "1", if the answer is "TRUE".


Example #3:
field[usrChosen1].chosen.field[skRanks].value

field[usrChosen1]
.
chosen
.
field[skRanks]
.
value

That's saying: travel to the field (on us) called "usrChosen1" (which stores the user's choice from a drop-down menu), then travel to the pick the user chose, then travel to the skRanks field on that pick (which tells you how many ranks the user has applied to that skill), and report the value of that field.

Here's how you might use that:
Code:
 if (field[usrChosen1].ischosen <> 0) then
  if (field[usrChosen1].chosen.field[skRanks].value >= 10) then
    field[usrChosen1].chosen.field[Bonus].value += 6
  else
    field[usrChosen1].chosen.field[Bonus.value += 3
    endif
  endif

"Travel to the drop-down menu on us - has the user selected a skill yet? If so, travel to the skill they selected - does that skill have 10 ranks in it yet? If so, add an untyped bonus of +6 to that skill. If not, add an untyped bonus of +3 to that skill." aka the Skill Focus feat.

Example #4:
hero.findchild[BaseRace].field[livename].text

hero
.
findchild[BaseRace]
.
field[livename]
.
text

That's saying: Travel to the hero container, then search among all the picks in that container for the first one you find that uses the BaseRace component, then travel to the livename field on that pick (livename stores the version of the name that will be displayed to the user), and report the text stored in that field.

Here's how that might be used:
Code:
hero.findchild[BaseRace].field[livename].text = "Mountain " & hero.findchild[BaseRace].field[livename].text

"Find our race and change its name to 'Mountain ' and whatever name is already there" ("Dwarf" would become "Mountain Dwarf", for example) (note the space in 'Mountain ', so that you don't get 'MountainDwarf'). This might be used by an Alternate Racial Trait, to rename its race.

In the next few posts, I'll look at each of the types of locations you might visit, and list where you can go from there, what questions you can ask while you're there, and what orders you can give Hero Lab while you're there.

If you're writing an Eval Script or an Eval Rule, you'll start out in the pick context. If you're writing a Prereq or an Exprreq, you'll start out in the container context (either hero or gizmo, depending on what container this item will be in once it's added).
 
Last edited:
Hero Context



Places you can travel to:
  • childfound[Child's Id] or child[[Child's Id]
    • test: childlives[Child's Id]
    • This travels to the pick context of a specific child. If there is more than one child with that Id, it will pick one at random to travel to. Generally, use childfound[] as opposed to child[] - if that child isn't actually there to travel to, child[] will report errors will be hard to understand. Childfound[] won't report any errors.
  • herofield[Field's Id]
    • This travels to the field context of a specific field on the special "herofield" pick that's used to store hero-wide information (this is actually a shortcut for hero.child[Totals].field[Field's Id]).
Questions you can ask:
  • tagis[Group Id.Tag Id]
    • TRUE/FALSE: Is the listed tag present here?
  • tagcount[Group Id.Tag Id]
    • How many of the listed tag are present here?
Instructions you can give:
  • assign[Group Id.Tag Id]
    • Add 1 copy of the listed tag here.
  • delete[Group Id.Tag Id]
    • Delete ALL copies of the listed tag here.
  • tagreplace[Group Id.Tag Id,Group Id.Tag Id]
    • Delete all copies of the first of those listed tags, then assign 1 copy of the second of those listed tags (this is a shortcut for delete[], then assign[]).
(Those lists are actually just the most common operations - a more complete list is available here: http://hlkitwiki.wolflair.com/index.php5/Container_Context and http://hlkitwiki.wolflair.com/index.php5/Hero_Context)
 
Last edited:
Pick Context



Places you can travel to:
  • field[Field Id]
    • This travels to the field context of the specific field that's within this pick.
  • hero
    • Travels to the hero container on the character.
  • container
    • Travels to whatever container this pick is in - either the hero or to a gizmo
  • parent
    • Only use this if you are sure you're in a gizmo, not the hero.
    • This travels to the pick context of the pick that contains the gizmo that contains this pick.
  • root
    • Test: isroot
    • Travels to the pick that bootstrapped this pick. Usually, this is used to get from a class special to the class.
  • linkage[varies]
    • Test: islinkage[varies]
    • This is only available on an archetype.
    • Travels to the pick context of the class that this archetype modifies.
  • linkage[skillattr]
    • Test: islinkage[skillattr]
    • This is only available on a skill.
    • Travels to the pick context of the attribute that this skill is linked to.
  • linkage
    • Test: islinkage

      [*] This is only available for Cleric Domains and Custom Abilities (like Rogue Talents, Wizard Schools, Barbarian Rage Powers, Sorcerer Bloodlines, etc.).
      [*]Travels to the pick context of the class this ability was added to.

    [*]gizmo
    • Test: isgizmo
    • This travels to the gizmo container that's within the pick. Remember that most picks will not have a gizmo.
    [*]gearholder
    • Test: isgearheld
    • This travels to the pick context of the pick this item is held within.
    [*]herofield[ Field's Id ]
    • This travels to the field context of a specific field on the special "herofield" pick that's used to store hero-wide information (this is actually a shortcut for hero.child[Totals].field[Field's Id]).
Questions you can ask:
  • tagis[Group Id.Tag Id]
    • TRUE/FALSE: Is the listed tag present here?
  • tagcount[Group Id.Tag Id]
    • How many of the listed tag are present here?
  • isuser
    • TRUE/FALSE: Was this added by the user? (If it's false, it must have been bootstrapped).
  • isgearlist
    • TRUE/FALSE: Are we allowed to hold other gear?
  • isholdable
    • TRUE/FALSE: Are we allowed to be held by another piece of gear?
  • gearcount
    • How many items are we currently holding?
Instructions you can give:
  • assign[Group Id.Tag Id]
    • Add 1 copy of the listed tag here.
  • delete[Group Id.Tag Id]
    • Delete ALL copies of the listed tag here.
  • tagreplace[Group Id.Tag Id,Group Id.Tag Id]
    • Delete all copies of the first of those listed tags, then assign 1 copy of the second of those listed tags (this is a shortcut for delete[], then assign[]).
These lists are the most common things you'll do in the pick context. A more complete list is available at: http://hlkitwiki.wolflair.com/index.php5/Pick_Context#transitions
 
Last edited:
Field Context

There are three types of fields - numerical, text, or menu, and each has different operations that can be performed.




Places you can travel to:
  • pick
    • Travels to the pick that contains this field
  • chosen
    • Test: ischosen
    • Menu fields only
    • Travel to the pick context of whatever the user chose in this menu
Questions you can ask:
  • isempty
    • Text fields only
    • TRUE/FALSE: Is this field empty/blank? (this will return 1 if the text is blank, and return 0 if there is some text in it).
Operations Available



(This can either be used to look up information on the field or to change the value of the field):
  • value
    • Numerical fields only
    • Returns the value stored in this field
  • text
    • Text fields only
    • Returns the text stored in this field
This list is only the most common things you'll do in the field context. A more complete list is available at: http://hlkitwiki.wolflair.com/index.php5/Field_Context#transitions
 
Gizmo Context



Places you can travel to:
  • childfound[Child's Id] or child[[Child's Id]
    • test: childlives[Child's Id]
    • This travels to the pick context of a specific child. If there is more than one child with that Id, it will pick one at random to travel to. Generally, use childfound[] as opposed to child[] - if that child isn't actually there to travel to, child[] will report errors will be hard to understand. Childfound[] won't report any errors.
  • hero
    • Travels to the hero context
  • parent
    • Travels to the pick context of the pick this gizmo is within
  • herofield[Field's Id]
    • This travels to the field context of a specific field on the special "herofield" pick that's used to store hero-wide information (this is actually a shortcut for hero.child[Totals].field[Field's Id]).
Questions you can ask:
  • tagis[Group Id.Tag Id]
    • TRUE/FALSE: Is the listed tag present here?
  • tagcount[Group Id.Tag Id]
    • How many of the listed tag are present here?
Instructions you can give:
  • assign[Group Id.Tag Id]
    • Add 1 copy of the listed tag here.
  • delete[Group Id.Tag Id]
    • Delete ALL copies of the listed tag here.
  • tagreplace[Group Id.Tag Id,Group Id.Tag Id]
    • Delete all copies of the first of those listed tags, then assign 1 copy of the second of those listed tags (this is a shortcut for delete[], then assign[]).
(Those lists are actually just the most common operations - a more complete list is available here: http://hlkitwiki.wolflair.com/index....tainer_Context)
 
Last edited:
Special Transition: Focus

Often, you'll need to do a lot of typing in order to travel to a particular thing. There's a special transition called the focus transition that you can use to "save your place", so that you don't have to do lots of typing if you need to do multiple things there.


Places you can travel to:
  • focus
    • Test: state.isfocus
    • travels to the pick context that's been assigned as the focus
Instructions you can give:
  • setfocus
    • Only available in a pick context
    • Sets the focus to this pick
  • state.clearfocus
    • Available from all contexts
    • Clears the focus if it's been set (and does nothing if no focus was set).
 
Last edited:
Special Transitions: Searching

Often, you don't know exactly what child you want to transition to, but you know some things about what it will be like. For example "I want to find a light weapon that deals piercing damage and is made of metal". Other times, you know there are multiple picks with the same Id. The child[] transition would only take you to one of them, and it would pick that one at random, so, you need a way to find all of them. That's handled by searching through a container to find those picks.

Code:
foreach pick in container from component where "test expression"
  nexteach

Replace container with either hero or gizmo. To use gizmo, you'll need to be starting in a pick that has a gizmo, or set up some set of transitions that ends in gizmo.

In that, replace component with the Id of a component that all of the things you're searching for have in common. To find this, add some examples of a few of the things you're trying to find to a test character, and look at their tags. There will be a section of tags whose Group Ids are all "component". Pick one of these - one that all of the things you're looking for will have.

Replace test expression with a tag expression that narrows down the list even further than just the component does. To find these tags, look at the tags on the example items you added, and compare them to the tags on things that are like those examples, but not quite.

If just the component will do the trick and will identify all the things you're searching for, you can leave out 'where "text expression"' entirely.

While you're in that foreach, you can use a special transition:
  • eachpick
    • Travels to the pick context that's currently being worked on
Remember that if you don't use the eachpick transition, you're still in the default place for this script, and from there, you can go to all the places you normally would, and do all the things you normally would.

An example:

Code:
foreach pick in hero from BaseSkill where "Helper.ClassSkill"
  eachpick.field[Bonus].value += 1
  nexteach

That will search through all the picks in the hero container that have the BaseSkill component and have the Helper.ClassSkill tag.

On each of the picks it finds, it will travel to the Bonus field for that pick, and add 1 to its value. In other words; "All our class skills get +1".


Once you're done with all the operations that apply to the things you're searching for, close your foreach with the following line:
Code:
nexteach

Sometimes, you know there will only be exactly one thing that matches what you're searching for (for example, you know that a character will have a single race, but you don't know which race the user will actually pick).

This is a special transition you can do from either the hero or gizmo contexts:

findchild[component,test expression]

component is the same as in a foreach, and test expression is also the same as in a foreach. As in a foreach, if you don't need an expression, you can leave it out (if you do, leave out the comma, too).

It's very common to use the setfocus instruction after findchild[] - that way, you don't need to repeat the search if there are lots of questions you want to ask on that pick and/or many things to change. Think of it as findchild[component,test expression].setfocus
 
Last edited:
Special Case: Prereqs

The context of a prereq or an exprreq is the container (either the hero or the gizmo) that this item is being added to (or is currently in, if the user has selected this item). This is different from the eval scripts, where the initial context is the pick that the script is running on.

In a prereq or an exprreq, there are some special instructions and special transitions that are available, and there are some restrictions on what you'll be able to accomplish.



Questions you can ask
  • @ispick
    • You can only use this by itself
    • It's a TRUE/FALSE test - it will return 1 if this has been added to the character and 0 if it's still in the list of things to test.
Operations you can perform
(these can either look up the current value of this special operator, or you can change its value)

  • @valid
    • You can only use this by itself
    • This stores whether the prereq has failed or not.
    • At the beginning of a prereq script, it is already set to 0.
    • To make the prereq succeed, set it to 1 (or any other value that's not 0).
Places you can travel
  • altthing & altpick
    • These travel to the pick the prereq is actually on - remember that the initial context for a prereq is the container. That differs from the initial context of an eval script, which is the pick. So, if you need to look up information on the pick for a prereq
    • If @ispick = 0, you must use altthing to travel to the pick. If @ispick = 1, you must use altpick.
Here's how altthing and altpick are used in practice:

Code:
if (@ispick <> 0) then
  altpick.something
else
  altthing.something
  endif

the .something is the same in each branch.
 
Last edited:
The link at the bottom of the Gizmo section doesn't seem to be working.

Fixed now. This forum has an aggravating bug in the auto-detection of pasted-in hyperlinks - it doesn't include the closing parentheses if the web address ends in one.
 
ENOUGH EXAMPLES!
can someone PLEASE just give me a COMPLETE GUIDE to the scripting language that is used in Hero Lab, please?
I NEED AND WANT the DEFINITIVE Reference Manual to this scripting language because honestly IT IS NOWHERE to be found!
and by reference manual I am talking something like an O'Reilly programming book but made about Hero Lab instead! PLEASE!

I AM SO SICK of not being able to find a REAL REFERENCE work!
AND NOBODY is really laying it ALL out in an ORDERLY fashion.... all i ever see are hob globs of LOOSE and CHAOTIC "examples" all over the internet with NO logical or orderly ORGANIZED presentation of what to do or how to do it!
I NEED TO SEE A SYSTEM please. NOT just random examples! :(
 
WHOA chill dude.

The core modding of Herolab is not the main reason it is here. The fact LWD allows us to use its complete script language to customize HL is truly amazing.

There is no such beast you ask for, just relax, take a breath. Best way to learn HL scripting and modding is to have a goal, start simple, and work forward. Read the info provided by LWD and the community. Do not hesitate to ask questions here nicely. The LWD staff and the amazing community here will likely either have answer for you or the bad news if its not possible.

I have learned a ton, with my work on two campaign worlds, and am approaching complete support in HL for both, and compare to many here I am but a newb. I have work through a lot of funstrations...<no typo> and if I hit a wall I can't climb I come here for the advice, and so far with out fail, I have left that wall behind me.

Just sit back, and pick your goals, and one by one you will find yourself over coming them and learning the scripting language at the same time.

There is no better way to learn, then by doing.
 
I agree with Exmortis =]
Best to just be chill, angry coding never works out.. though I do understand ProphetPX's frustration. For pretty much every other scripting/programming you can find a unified and complete syntax, but not for Hero Lab.
Still, it's pretty cool that Hero Lab is so customizable ^^
 
I sympathize as well. I would push a busload of nuns off of a cliff just to have a "tag dictionary" that lays out all of the Pathfinder tags, what uses each one, and the effects of applying them. If it was searchable, I would pick a cliff that was directly above a burning orphanage. And if I told you what I would do for a complete reference on the scripting language, the CIA would drone-strike my house, on the off-chance that I meant a word of it.

That said, I know from painful experience that software developers are often too close to the product to be able to write clear documentation on it, and technical writing is a whole different skillset that LWD may not have in-house. That means any "O'Reilly's for Hero Lab" project would likely require an outside contractor, and that means spending money that otherwise could be spent on adding more features and data packages to Hero Lab. Not necessarily a good ROI, given that us modders are a rather small part of their overall customer base.

Finally, ProphetPX, have you looked at the wiki? It's far from comprehensive, and it isn't the easiest thing to navigate, but it is handy for looking up functions and what methods and transitions are available from a particular context. It's the closest thing to what you're asking for that currently exists. I frequently refer to the Language Intrinsics and Pick Context pages in my own work.

These forums are an excellent resource, too. I've said it before, but for every time I've had to post a question here, there have been 10 or so times that I haven't needed to post one because I found what I needed by searching older threads.
 
Last edited:
I've dropped ALMOST THREE HUNDRED DOLLARS on this product because i happen to LOVE using it!
What i did not expect was that there was NO SYSTEMATIC BOOK that laid out all the scripting language that i could learn from. I've looked at the stupid wiki, many videos (EVEN the GenCon one) AND the HORRIBLE PDF file that was on the website (sorry but it is very bad).... NOTHING is helping me! Copying from other items or "things" in the editor is NOT helping either. I need to learn HOW TO CODE it!!!

I know XML, and some Java, and am not unfamiliar with object oriented stuff.
But this "guesswork" and "trial and error" stuff is NOT COOL!!!!
 
Due to posts made here, in other threads, and in PMs to me (Liz) that do not follow the forum rules (specifically respect and civility, constructive posts, and thinking before posting), ProphetPX has been placed on temporary probation. If any users have questions or concerns about the decision, please PM me directly.
 
That's too bad, I do understand his frustration.

I am a horrid coder, and I find scripting really hard to wrap my wee brain around.

However I have achieved a fair amount using the Information/tools provided and a lot of help from this forum.

I think the poor guy just needs to take a vacation from it, and come back to the table with a cool, refreshed, relaxed mind.
 
Back
Top