Edit 7/19/2010: Since I first wrote this post, I have learned more about MapTool macros, and you can find the improved information at this post. However, I’ve left the original post below for posterity – and as an example of how to learn how to improve your macro writing, rather than just giving the finished product.
During our first actual gaming session with MapTool, I was pleasantly surprised to discover that my players liked keeping track of their characters’ hit points within the program, right on the character sheet that pops up whenever they would mouse over their character’s token. They did this despite the fact that changing their HP involved double-clicking the token, navigating to the Properties tab of the Edit Token dialog, deleting the current HitPoints value and entering the new value.
Given that they like keeping track of HP in MapTool, I figured the least I could do would be to make it easier for them. I wanted to create a button that would let them decrease their HP and another button that would let them heal. And while I COULD have stopped there, I got into it and wanted to make this even slicker.
Before I could put the new macros into action, I had to edit my characters’ properties. I needed the MaxHP value (so that healing couldn’t take the character above it). And while I didn’t technically NEED the Bloodied value to be on the character sheet (macros could calculate it based on MaxHP), I discovered that MapTool will let you specify factors that are derived from other factors. Here are the properties I now use for the Health section of my characters’ stat sheets:
Health properties
*@—–HealthStats—–:-
*@HitPoints:10
*@TempHP:0
*@MaxHP:10
@BloodiedHP:{FLOOR(MaxHP/2)}
*@SurgesLeft:6
*@SurgeValue:{FLOOR(MaxHP/4)}
@DailySurges:6
Note that the * means that the variable will be displayed on the mouse-over character sheet and the @ means that it will be visible only by the token’s owner and the GM. (Side note: This means that my players won’t be able to see stats for monsters, since they don’t own the monster tokens – this is good.) The header line (HealthStats) is technically a property with an assigned value of “-“, which I’ve added just for looks on the pop-up sheet (there’s a separate section now for defenses and so on). SurgeValue isn’t used in my macros, but I wanted it on the sheet so my players could look it up easily whenever they spend a surge.
These macros ended up getting more complex than I intended for them to be, so I’ll just put the finished versions below and then discuss each one. I’ll start with the macro that adds temporary hit points, as it’s the simplest.
Temporary hit points macro
[h: TempsAdded=AmountOfTempHPGained]
[h: CurTemps=getProperty(“TempHP”)]
[if(CurTemps>=TempsAdded), CODE:
{Already has [CurTemps] temporary hit points, so no temps were added.};
{[h: setProperty(“TempHP”,TempsAdded)]
Now has [TempsAdded] temporary hit points.}
]
This macro first creates a prompt that asks the player to enter a value for AmountOfTempHPGained. There are ways using the INPUT command to make this look prettier, but I haven’t bothered with them yet. Once the player has said how many temps they’re gaining (let’s say 3), that’s stored as TempsAdded. The macro finds out how many temps the player has at the moment (CurTemps) and then checks to see if the new temps are greater than the old. Since temporary hit points don’t stack in D&D 4e (if you have 5 and gain 3 more, you just have 5, not 8), the macro simply prints a “no new temps for you” message if they already have at least as many as they’re adding. Otherwise, it sets the TempHP value on the character sheet to the amount of temps that were added and tells the player the new total. Not too hard.
Next up is the macro to gain actual hit points – the healing macro.
Healing macro
[h: Heal=AmountOfHPGained]
[h: CurHP=getProperty(“HitPoints”)]
[h, if(CurHP>=0), CODE:
{[NewHP=CurHP+Heal]};
{[NewHP=Heal]}
]
[h, if(NewHP>getProperty(“MaxHP”)), CODE:
{[NewHP=MaxHP]
[Heal=MaxHP-CurHP]};{}
]
[h: setProperty(“HitPoints”,NewHP)]
[h: Bloodied=getProperty(“BloodiedHP”)]
Gains [Heal] hit points and is at <b>[NewHP]</b> hit points.
[if(NewHP>Bloodied && CurHP<=Bloodied && CurHP>0), CODE:
{She is no longer bloodied.
[h: setState(“Bloodied”,0)]};
{}
]
[if(CurHP<=0 && NewHP<=Bloodied), CODE:
{She is no longer dying, but she is still bloodied.
[h: setState(“Unconscious”,0)]};
{}
]
[if(CurHP<=0 && NewHP>Bloodied), CODE:
{She is no longer dying, and she is no longer bloodied.
[h: setState(“Unconscious”,0)]
[h: setState(“Bloodied”,0)]};
{}
]
[if(NewHP==MaxHP), CODE: {She is at maximum health.}; {}]
This one starts like the last one, popping up an input box that asks the player to say how many hit points they’re gaining, saving that number as Heal. It then gets the character’s current HP.
- If current HP is greater than zero, the macro sets the player’s HP to the current HP plus the healed amount.
- If current HP is less than zero, the macro follows D&D 4e rules by setting the player’s life total to the healed amount (healing starting from zero rather than from a negative number).
The macro also checks to see if the healing would put the character’s hit points at or above their maximum hit points; if so, it only heals up to the maximum. It prints a message with the amount of HP healed and the new HP total.
The macro also gets the PC’s bloodied value from the character sheet and prints out some additional messages depending on where the character started with HP and where they ended up.
- If the PC was conscious but bloodied and is not bloodied any more, the macro prints a message saying as much and then removes the “Bloodied” state from the character (which shows up in my campaign as a little red icon in the corner of the token).
- If the PC started off dying and ended up not dying but still bloodied, the macro says as much and then removes the “Unconscious” state from the character (which shows up in my campaign as a gray X across the character’s portrait).
- If the PC started off dying and ended up unbloodied, the macro says so and removes both the “Bloodied” and “Unconscious” states from the character.
Finally, if the PC ends up at maximum hit points, the macro says that, too. This is helpful in cases where the amount healed is less than the amount entered because the full amount would have put the PC above their max HP. This way, the player understands what happened.
Now for the damage macro. I originally wrote this one before the healing macros, and I forgot about temporary hit points when I wrote it, so it had to be re-done. This has made it rather complex in appearance.
Damage macro
[h: Dmg=AmountOfDamageTaken]
[h: CurHP=getProperty(“HitPoints”)]
[h: CurTemps=getProperty(“TempHP”)]
[h: Bloodied=getProperty(“BloodiedHP”)]
[h: Dead=-1*Bloodied]
[if(CurTemps==0),CODE:
{
[h: NewHP=CurHP-Dmg]
Takes [Dmg] damage and is at <b>[NewHP]</b> hit points.
[h: setProperty(“HitPoints”,NewHP)]
};
{
[if(Dmg<=CurTemps), CODE:
{
[h: setProperty(“TempHP”,CurTemps-Dmg)]
[h: NewHP=CurHP]
Takes [Dmg] damage, losing [Dmg] temporary hit points. She how has [CurTemps-Dmg] temporary hit points and <b>[CurHP]</b> regular hit points.
};
{
[h: HPDmg=Dmg-CurTemps]
[h: NewHP=CurHP-HPDmg]
[h: setProperty(“TempHP”,0)]
[h: setProperty(“HitPoints”,CurHP-HPDmg)]
Takes [Dmg] damage, losing [CurTemps] temporary hit points and [HPDmg] regular hit points. She now has no temporary hit points and <b>[NewHP]</b> regular hit points.
}
]
}
]
[if(NewHP<=Bloodied && CurHP>Bloodied && NewHP>0), CODE:
{She becomes bloodied.
[h: setState(“Bloodied”,1)]};
{}
]
[if(NewHP<=0 && NewHP>Dead && CurHP>0), CODE:
{She is now dying.
[h: setState(“Unconscious”,1)]};
{}
]
[if(NewHP<Dead), CODE:
{She is dead.
[h: setAllStates(0)]
[h: setState(“Dead”,1)]};
{}
]
All right, let’s break this down. This macro starts by asking the player how much damage they’re taking. It pulls in the current hit points, current temporary hit points and bloodied value from the character sheet and calculates the “Dead” HP value (the negative of the bloodied value). The code then branches.
- If the player doesn’t have any temps right now, the new HP is set to the old HP minus the damage taken, and the player is told how much damage is taken and where their hit points stand now.
- If the player does have temporary hit points, the macro checks to see whether they’ll all be used up by the damage or not.
- If they have more temps than they’re taking in damage, the damage is subtracted from the temps and the player is told how much damage they took, how many temps they have left and what their total HP is.
- If the damage is enough to eat all of the temps and then some, the temps are wiped out, the remainder is subtracted from the actual hit points, and a message tells the player what happened.
Now the branches are done (the player has gotten a message telling them how much damage they took and where their HP situation is now). The rest of the code checks to see if the character went from unbloodied to bloodied, conscious to unconscious, or alive to dead. If any of those happen, the proper states are set and the proper messages are sent to the text window.
Finally, I realized that players will probably want to keep track of their healing surges as well, so I created a simple little macro to let them remove a surge from their total (note that actually gaining hit points is handled independently through the healing macro above). Having done that, I figured I might as well create a macro to let them add a surge back (useful in case they click the “spend a surge” button by accident or take an extended rest). The code for these is as follows:
Remove a surge:
[h: CurSurges=getProperty(“SurgesLeft”)]
[if(CurSurges>0), CODE:
{[h: setProperty(“SurgesLeft”,CurSurges-1)]
Spends 1 healing surge. She has [CurSurges-1] [if(CurSurges!=2, “surges”, “surge”)] remaining.
};
{Has no healing surges left to spend.}
]
Regain a surge:
[h: CurSurges=getProperty(“SurgesLeft”)]
[if(CurSurges<getProperty(“DailySurges”)), CODE:
{[h: setProperty(“SurgesLeft”,CurSurges+1)]
Regains 1 healing surge. She has [CurSurges+1] [if(CurSurges!=0, “surges”, “surge”)] remaining.
};
{Already has her full daily allotment of [CurSurges] healing surges.}
]
You’ll note that these macros do a couple of minorly fancy things. First, they check to make sure that the player either has a surge left to spend or isn’t already at their maximum surge value on the adding side. Second, they appropriately handle the singular/plural on surge/surges. I didn’t bother with this on the hit points macro, so there you can see things like “Violet: Takes 10 damage and is at 1 hit points.” Annoying, but not worth fixing because the code is messy enough already!
In case you were wondering, yes, I did use feminine pronouns throughout these macros because all three of my players are using female characters (despite the fact that one player is male). If this were not the case, I could:
- Awkwardly switch to gender-neutral pronouns
- Edit the pronouns in the macros independently for each character
- Create a property that indicates whether the character is male or female and then edits the pronouns appropriately
If I were doing this for broad distribution, I’d take the latter approach. In my small game, though, I’ll probably go with the second approach if a male character ever comes up.
I’ve stored these macros in a package (along with skill checks, which I’ll cover in a later post) in case you’re interested (available here or on the downloads page). I’m excited to see how my players will like them!