MapTool Macros – Damage and healing

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!

5 thoughts on “MapTool Macros – Damage and healing

  1. It’s amazing how different groups use MapTool in different ways.

    My group basically used the table for placement of characters but clung to their character sheets and dice.

    I had thought to use one of the Frameworks placed out by the community in support of 4e. The one I’ve tried is Rumble’s 4e (http://forums.rptools.net/viewtopic.php?f=33&t=7736). It works, but I went back to just rolling dice and having the monster generator up.

    Just out of curiosity, do you have a DDI account?

    • I was surprised that my group wanted to keep track of life totals in MapTool, and while I’m not surprised that Lane and Zach like the macros for dice rolling, I was a little surprised that Barbara was using them. Keep in mind that the first time this group ever played was with an impromptu game in a hotel room in Florida where none of us had dice, so we had to use dice rollers on our computers and phones.

      Funny you should mention Rumble’s framework – that’s on my list of topics for upcoming posts! I only discovered it (and other frameworks) last weekend, and I was very impressed. I thought about switching over for my game, but I actually love writing macros so I’ve decided to just custom write them for my own game.

      I do have a DDI subscription, and I know that Rumble’s framework would allow me to do some importing of characters and monsters from the DDI tools, but I probably won’t use that, at least for now. Is there another advantage of using DDI with MapTool that I don’t know about yet?

  2. Not that I’m aware of. I wasn’t aware that Rumble’s framework allowed importing characters!

    I was reading on the forums that a user is trying to get TokenTool to open a .dnd4e and create full N/PC token out of it.

    • Yes, apparently Rumble’s framework lets you import character info from Character Builder (indirectly). Here’s the quote from Rumble’s instructions:

      Importing PCs
      To import a PC Summary from the character builder, follow these steps:
      Hit the F5 key to launch the Import Character Summary frame
      Paste the Summary text from the Character Builder or the first two pages of a Character Builder character sheet (convert it to PDF first!) into the text area, and hit save.
      The summary will be read and the basic stats from that will be generated. Note: Powers are not imported. To import powers, see the next section!

      I haven’t tried it, but I’m guessing it would work.

      Interesting note about using TokenTool to open a .dnd4e file… I thought TokenTool was just about the image. I guess I don’t know what’s in the .dnd4e file!

  3. Good to know! In a few months I’ll have time to mess around with MapTool again. I’ll probably start with Rumble’s work and pick and choose what I want to use.

    The .dnd4e file is a XML file that’s been renamed to .dnd4e. You can open it in notepad and look at how it’s laid out.

    TokenTool is meant to just make the token image. Normally you’d import the token into MapTool and then re-save it. The work that’s going on is to have TokenTool use the dnd4e file to fill in the token automatically. If this ends up working out, I can have my character’s just send me updated tokens when they level up!

Leave a Reply to OnlineDM Cancel reply