Advanced MapTool macros part 1: Intro to JSON objects

Over the past few weeks, I’ve been working on what I expected would be a not-too-hard MapTool macro project. I wanted to create a macro (or set of macros, as it turned out) for putting conditions on tokens that would also keep track of when those conditions needed to end. Seemed simple enough; after all, I already had nice little macros that would toggle a condition on or off of a selected token or group of tokens. Those looked like this:

[h: SelectedTokens=getSelected()]
[FOREACH(TokenID, SelectedTokens, " "), CODE:
 {[h: NewState=if(getState("Dazed",TokenID)==1,0,1)]
 [h: setState("Dazed",NewState,TokenID)]

However, in figuring out how to handle the automatic tracking of the condition end time, I had to delve deeper, trying to avoid Balrogs as I went.

Yes, dear readers: I had to learn about JSON! (Cue horrified screaming)

JSON stands for JavaScript Object Notation, and it’s something I had seen used by the REAL heavy lifters among MapTool macro writers. They had JSONs all over the place in their campaigns, and I tried my best to avoid them. They looked… intimidating.

I’ll warn you all right now, if you’re just looking for casual stuff about MapTool, skip this series of posts. This is heavy-duty macro programming compared to what I’ve written before. It still pales in comparison to the stuff written by the folks who create full-on MapTool frameworks, but it’s more than I’ve done in the past. However, if you need to learn about using JSONs, I hope to present it in an easy-to-follow manner.

What is a JSON object?

There are types of JSON in MapTool: JSON objects and JSON arrays. I’m going to talk about JSON objects today.

A JSON object is a single variable or property enclosed in braces {} that can hold several pieces of information.

For instance, here is a JSON object I ended up creating for my state-tracking macros:

{"TokenName":"Brute 1","State":"Cursed","EndCount":2,"EndRound":1,"AutoEnd":"1"}

This single object contains 5 pieces of information: The TokenName (Brute 1), the State on that token (Cursed), the count in the initiative order when that state will end (2), the round in which it will end (2) and a variable that indicates whether I want the condition to simply end automatically (1 means “yes” in this case) or not.

How do you build a JSON object?

If I wanted to build the object above, I could do it by assigning as a regular variable in MapTool, enclosing the whole thing in single quotes:

[h: MyJSONObject='{"TokenName":"Brute 1","State":"Cursed","EndCount":2,"EndRound":1,"AutoEnd":"1"}']

I could also use the ADD function if I had already created separate variables for, say, TokenName and State:

[h: CurrentTokenName="Brute 1"]
[h: CurrentState="Cursed"]
[h: MyJSONObject=add('{"TokenName":"', Brute 1, '","State":"', Cursed, '","EndCount":2,"EndRound":1,"AutoEnd":"1"}']

There’s also the option of using some of MapTool’s JSON functions, such as json.set:

[h: MyJSONObject=json.set("{ }", "TokenName", CurrentTokenName, "State", CurrentState, "EndCount", 2, "EndRound", 1, "AutoEnd", 1)]

Note that there are no single quotes needed with json.set. I start with the empty braces in quotes to let MapTool know that this will be a JSON object rather than a JSON array. I then list the key/value pairs, separated by commas.

Getting information from JSON objects

Once I’ve created this object, what the heck do I do with it? Well, assuming I save it as the value of a property of some token, I can have other macros refer to this property later to get information out of it. I do this with MapTool’s json.get function.

First, let’s say I have a library token called lib:LibToken1. Great name, right? And let’s say it has a property called StateObject, which starts off being set to 0. Now let’s assume that I assign my new JSON object to this property as follows:

[h: setProperty("StateObject", MyJSONObject, "lib:LibToken1")]

So, I set the StateObject property of the token called lib:LibToken1 equal to MyJSONObject.

In a later macro I can retrieve this property from the token and extract the information:

[h: CurrentStateObject=getProperty("StateObject","lib:LibToken1")]
[h: CurrentTokenName=json.get(CurrentStateObject, "TokenName")]
[h: CurrentState=json.get(CurrentStateObject, "State")]

The first line gets the StateObject property from the lib:LibToken1 token (which, remember, is equal to whatever I put in MyJSONObject) and stores it as CurrentStateObject (so CurrentStateObject=MyJSONObject). Then I can extract the TokenName value from that object and store it as CurrentTokenName using json.get. I do the same for the State value. I could do the same for the EndCount, EndRound and AutoEnd values. And then I can do whatever I like with these values inside my macro.

Why would you use a JSON object?

This is the question that kept me away from learning about JSON stuff for so long. Why do I even need it?

In lots of cases, you don’t actually NEED to use JSON, but it can make life easier. Where I decided I finally needed to use it was when I wanted to have a single property on a token that could hold lots of different stuff (in this case, information about states on tokens and when they end). The JSON object above is an example (actually as a piece of a JSON array) that appears in the StatesArray property of a token I created specifically to hold this kind of thing. Without using JSON, I would need to create a whole bunch of different properties on the token – one each for TokenName, State, EndCount, EndRound and AutoEnd. I could do that, but it would be messier.

And if I wanted to have a varying number of these objects – one for each token and state in the game – I’d need to create a huge multitude of properties, and I’d have to set up enough of them in advance so that I’d never run out. If I have 20 minions each getting slowed by a controller’s blast, well, I’d better have 100 properties set up in advance. If they’re being slowed and blinded, now I need 200 properties.

There’s got to be an easier way, and there is: JSON arrays. That’s the next post!

2 thoughts on “Advanced MapTool macros part 1: Intro to JSON objects

  1. Pingback: Links of the Week: October 31, 2011 | KJD-IMC - KJDavies "In My Campaign" Articles

  2. Pingback: MapTool – Creating macros from macros, plus encode and decode | Online Dungeon Master

Leave a Reply