MapTool: Star Wars d6 campaign framework with NewbieDM

I mentioned last week that I had gotten together with Enrique of NewbieDM.com and Mark Meredith of Dice Monkey on Wednesday night to help them out with some MapTool questions regarding the Star Wars d6 system (a game I know absolutely nothing about). I built a macro that rolled dice in the way I understood the Star Wars d6 system to work based on Mark’s description.

I later learned that the odd rule of the wild die not only exploding on a 6 but also penalizing the player on a 1 is an optional rule; the default rule is that the wild die just explodes. There’s also another optional rule that states that a 1 on the wild die will give you a 5/6 chance of the penalty I originally built (the die counts as zero, and you drop the highest non-wild die, too) and a 1/6 chance of having a plot-related complication instead. In the comments of that original post, I built the alternative macro with the possible complication.

I also learned that players often have “pips” which count as static bonuses to their rolls. NewbieDM stepped in on the comments to modify the macro to ask for the pip bonus. Nice work, Enrique!

NewbieDM then took the next step and created a full-on campaign framework file for Star Wars d6. He found some excellent artwork for the backgrounds (I especially love the star field). He and I collaborated on setting up campaign properties. I extended his work a little further to create a sample token with some macros on it for skills (Dexterity, Knowledge, etc.); one set for the default rules and one set for the rules that include a penalty for a 1 on the wild die. I didn’t include a set for the optional 1/6 chance of getting a “complication” if you get a 1 on the wild die, but the code is on the blog if you need it.

My version of the campaign framework file (built on NewbieDM’s) is available here.

It’s been fun learning a little bit about a new game and being able to help create something useful for people who play the game. I hope I get the chance to try it out myself sometime!

MapTool macro: Star Wars d6 / OpenD6 dice

I’m beginning to like Twitter.

Wednesday evening, I happened to check Twitter just before heading to bed. I was just in time to see an exchange between @NewbieDM (aka Enrique of NewbieDM.com) and @MarkMeredith (aka Dice Monkey). They had just finished trying to play some Star Wars d6 via Google+ hangouts, and it hadn’t worked all that well. Enrique was about to show Mark some MapTool stuff. I chimed in, and they invited me to join them on Skype.

Even though he hasn’t been using MapTool very long, Enrique has already built some extensive stuff for his Neverwinter campaign (using my MapTool framework as a base, I’m humbly proud to say). He started showing Mark the ropes, and it soon became clear that Star Wars d6 was a little bit different in terms of the way die rolling works. I knew nothing about the game, so Mark explained it.

The basic dice mechanic is this (as I understand it, this is the mechanic for all OpenD6 games):

  • You roll a certain number of six-sided dice, depending on your skill at the task at hand. For this example, we’ll say you have a skill of 3, so you’re rolling 3d6.
  • One of the dice is the wild die; the other dice are rolled normally.
  • If you roll a 6 on the wild die, it “explodes”. That is, you roll it again and add both rolls together. If you roll another 6, you keep on going.
  • However, if you roll a 1 on the wild die, it counts as a zero, and it also cancels out the highest non-wild die that you rolled. So, if you roll a 2 and a 3 on your normal dice and a 1 on the wild die, your total is just 2 (because the 1 on the wild die cancels out the 3 from your best normal die).

I knew that MapTool had a built-in roll option to handling exploding dice, but I don’t know of any roll options to have a certain die cancel another die roll. So, I wrote a macro:

[h: x=input("NumDice|0|How many dice are you rolling?")]
[h: abort(x)]

This brings up a prompt for the user to tell the program how many dice to roll. If they hit Cancel, the macro stops.

[h: RegTotal=0]
[h: RegMax=0]

I establish starting values of zero for the total of the regular (non-wild) dice and the maximum of any regular die.

Regular dice:
[for(i, 0, NumDice-1), CODE:
 {

I display the words “Regular dice: ” in the chat window, then start a loop. Note that loops begin with 0 rather than 1 in MapTool by default, so I go with that. I want to loop through all of the dice except the wild die, so I stop at NumDice-1. I then open a CODE block with a curly bracket; everything in this block will be executed a number of times equal to the number of dice minus one.

  [NewRoll=d6]

First, I roll a d6 and store the value as NewRoll. Note that I didn’t use the h: roll option here as I do in most lines of code. This is because I don’t want the value of NewRoll to be hidden (the h:). Since this is a FOR loop, MapTool will put a comma between the iterations. So, if this was the only thing in the CODE block, MapTool would display “Regular dice: 2, 4” if it rolled a 2 and then a 4 on the two iterations.

  [h: RegTotal=RegTotal+NewRoll]
  [h: RegMax=if(NewRoll>RegMax,NewRoll,RegMax)]
 }
]

I add this new die roll to the running total of the regular dice (which started at zero). I then check to see if this new roll is higher than any of the previous regular die rolls. If it is, I set the value of RegMax to equal the new die roll; otherwise, I leave RegMax where it was. I then close the FOR loop.

[h: WildResult=d6e]
<br>Wild die=[WildResult]

Now I roll the wild die and store the result as WildResult. I use an “e” on the end of the die roll expression to represent “exploding” which MapTool already has built in. Nice! I then put in a line break (the <br>) in the chat window and then display the words “Wild die=” followed by the result of the exploding die roll.

[h: FinalTally=if(WildResult==1, RegTotal-RegMax, RegTotal+WildResult)]
<br>Total=<b>[FinalTally]</b><br>

I now figure out and display the final result of the whole roll. If the wild die was a 1, the total for the roll is whatever I rolled on the regular dice, minus the highest regular die (the 1 from the wild die is not added). Otherwise, the total for the roll is the total of the regular dice plus the result of the wild die (including any explosions). I pop in another line break and display the final result in bold (the <b> and </b> surrounding the value of FinalTally).

The result will look something like this:

Regular dice: 2 , 3
Wild die=2
Total=7

There you have it – the basic Star Wars d6 dice macro! Now I just need to learn to play the game.

-Michael, the OnlineDM (@OnlineDM1 on Twitter)

 

Complete macro:

[h: x=input("NumDice|0|How many dice are you rolling?")]
[h: abort(x)]

[h: RegTotal=0]
[h: RegMax=0]

Regular dice: 
[for(i, 0, NumDice-1), CODE:
 {
  [NewRoll=d6]
  [h: RegTotal=RegTotal+NewRoll]
  [h: RegMax=if(NewRoll>RegMax,NewRoll,RegMax)]
 }
]

[h: WildResult=d6e]

<br>Wild die=[WildResult]
[h: FinalTally=if(WildResult==1, RegTotal-RegMax, RegTotal+WildResult)]
<br>Total=<b>[FinalTally]</b><br>

MapTool: Using the latest version

I first discovered MapTool in May 2010. At the time, the most up-to-date version of the program was good ol’ 1.3.b66. That’s what I downloaded, and that’s what I kept using for about a year and a half.

Why? Well, first of all, it worked. Second, I had heard that certain things that worked in older versions (macros, etc.) would not necessarily work if you tried them out in a newer version. Third, new builds kept coming out regularly, and I didn’t want my players to have to constantly download new programs just to connect to my game.

Recently, I was browsing the MapTool wiki and forums and found some discussion about the program’s performance. Specifically, I saw a note that moving a whole bunch of tokens at once was faster in newer builds.

Now, I don’t have many complaints about MapTool, but it’s definitely been a major annoyance to want to move the entire party from one section of the map to another and having to wait 30 seconds for MapTool to make this happen. So, I downloaded the current version of MapTool, 1.3.b86 (as of this writing), which has been the most recent version for months (and thus pretty stable).

Woo hoo – I can now move mobs of tokens across the map instantly! I can also run a macro on a whole bunch of tokens at once – such as when I have a bunch of enemies that are invisible to the players and I want to run my “Toggle Visibility” macro on all of them. Previously, the tokens would blink into existence one by one (which was a kind of neat effect, I suppose, but not really what I wanted). Now – poof, they all appear! Awesome!

Best of all, I haven’t found any macros that have broken yet. I try to keep my macros pretty straightforward, of course, and I’m guessing that helps. But every adventure I’ve opened so far in 1.3.b86, even though it was created in 1.3.b66, has had no problems.

The real test will come on Friday, when my regular players will have downloaded the new software and will try playing with it together. Honestly, I’m expecting it to be a non-issue, but we shall see.

So, the moral of the story for me is: Use the latest version of MapTool, as long as it’s been out for, say, a month with no updates. I don’t want to update constantly, but in this case the update is definitely worth the trouble.

MapTool macro: Attack and defense modifier states

More MapTool macro fun! Yes, I’m a nerd and proud of it.

In a game like Dungeons and Dragons 4th Edition, it’s pretty common to get temporary bonuses to attack rolls or defenses. When you’re playing with pen and paper, you have to keep track of these yourself. When you’re using MapTool, the program can help.

Now, I’m sure that some of the snazzier MapTool frameworks out there will handle temporary modifiers in super-fancy ways that actually change the calculation of attacks based on these modifiers and so on. I’m not looking for any of that. I’m simply looking for a visible reminder on a token that it has a temporary bonus or penalty.

I started creating +2 attack and-5 attack and +2 defense states in a piecemeal manner months ago. As PCs and monsters in my games started getting powers that could apply these bonuses or penalties, I created states that would remind me of them. I would then turn these states on and off very manually – right click on the token, find the right state, click on it. Repeat to turn it off.

Well, I’m sick of that, so I decided to automate the process.

First, I created a set of 20 token states: +1 to +5 attack, -1 to -5 attack, +1 to +5 defense and -1 to -5 defense. They look something like this:

      

Depending on whether I’m using MapTool online or with my projector setup, I either display these states as 3×3 grid images (online) or 2×2 grid images (projector – the larger images show up better). The red boxes are for attack (or damage) and the blue boxes are for defenses. I use 80% opacity, so you can still make out a little of the token art behind the states.

A monster with +5 to attack, one with -3 to defense, and one with +2 to attack and defense

For a while, I was creating individual toggle buttons for my states. Click a token, then click the “+2 Attack” button, and the +2 Attack state will toggle on or off. Now that I have 20 of these states, I decided to streamline. Rather than 20 buttons, I have two: One to set attack modifiers and one to set defense modifiers.

Attack bonus macro (download the macro)

[h: x=input("NewMod|0|What is the token's new attack modifier?")]
[h: abort(x)]

I start by asking for the new attack modifier in a pop-up; if the user clicks the Cancel button, the macro ends. Note that the user can specify a +2 bonus as either “2” or “+2”; the macro works either way.

[h: SelectedTokens=getSelected()]
[FOREACH(TokenID, SelectedTokens, " "), CODE:

I create a list of token IDs called SelectedTokens for however many tokens are currently selected, and then I loop through each of these tokens to perform the same code on them. This lets me apply (or remove) a bonus or penalty to a bunch of tokens at once.

 {[if(NewMod>5 || NewMod<-5), CODE: {[assert(1==0,add("<b>Error</b>: Attack modifier must be between -5 and +5"),0)]}; {}]

I throw off an error message if the user tries to enter a number over 5 or under -5, since that’s the range of states I’ve created.

  [h: OldMod=getProperty("AttackState",TokenID)]
  [h: OldState=if(OldMod>=0, add("+", OldMod, " Attack"), add(OldMod, " Attack"))]
  [h: NewState=if(NewMod>=0, add("+", NewMod, " Attack"), add(NewMod, " Attack"))]

I figure out what the current value of the token’s AttackState property is (a number from -5 to 5), and then convert this to a string like “+2 Attack” or “-3 Attack”. This corresponds to the names of the states in my campaign file. I do the same for the new attack modifier, getting the appropriate state name.

  [h, if(OldMod==0), CODE:{}; {[h: setState(OldState,0,TokenID)]}  ]
  [h, if(NewMod==0), CODE:{}; {[h: setState(NewState,1,TokenID)]}  ]

If the new or old modifier is zero, I don’t try to change it (since no state is displayed on the token for a zero bonus). Otherwise, I turn off the old state (setting it to false, or 0) and turn on the new state (setting it to true, or 1).

  [h: setProperty("AttackState", NewMod, TokenID)]
    }
   ]

I set the value of the AttackState property to whatever the user entered, so that the macro can reference that property the next time it’s run. I then close the CODE block and the FOREACH loop that I started at the top. Voila!

The whole macro is as follows:

[h: x=input("NewMod|0|What is the token's new attack modifier?")]
[h: abort(x)]

[h: SelectedTokens=getSelected()]
[FOREACH(TokenID, SelectedTokens, " "), CODE:
 {[if(NewMod>5 || NewMod<-5), CODE: {[assert(1==0,add("<b>Error</b>: Attack modifier must be between -5 and +5"),0)]}; {}]
  [h: OldMod=getProperty("AttackState",TokenID)]
  [h: OldState=if(OldMod>=0, add("+", OldMod, " Attack"), add(OldMod, " Attack"))]
  [h: NewState=if(NewMod>=0, add("+", NewMod, " Attack"), add(NewMod, " Attack"))]
  [h, if(OldMod==0), CODE:{}; {[h: setState(OldState,0,TokenID)]}  ]
  [h, if(NewMod==0), CODE:{}; {[h: setState(NewState,1,TokenID)]}  ]
  [h: setProperty("AttackState", NewMod, TokenID)]
    }
   ]

Defense bonus macro (download the macro)

The defense macro is exactly the same as the attack macro – just replace “Attack” with “Defense”.

[h: x=input("NewMod|0|What is the token's new defense modifier?")]
[h: abort(x)]

[h: SelectedTokens=getSelected()]
[FOREACH(TokenID, SelectedTokens, " "), CODE:
 {[if(NewMod>5 || NewMod<-5), CODE: {[assert(1==0,add("<b>Error</b>: Defense modifier must be between -5 and +5"),0)]}; {}]
  [h: OldMod=getProperty("DefenseState",TokenID)]
  [h: OldState=if(OldMod>=0, add("+", OldMod, " Defense"), add(OldMod, " Defense"))]
  [h: NewState=if(NewMod>=0, add("+", NewMod, " Defense"), add(NewMod, " Defense"))]
  [h, if(OldMod==0), CODE:{}; {[h: setState(OldState,0,TokenID)]}  ]
  [h, if(NewMod==0), CODE:{}; {[h: setState(NewState,1,TokenID)]}  ]
  [h: setProperty("DefenseState", NewMod, TokenID)]
    }
   ]

I hope this type of macro is useful for folks out there. As always, let me know if you have questions about my macros or requests for new macros. I love this kind of thing, as you can no doubt tell!

Note: All macros were generated with version 1.3.b66 of MapTool, but they work with 1.2.b86 as well.

Download the properties for online games with these states

Download the properties for projector games with these states

Download my complete campaign template for online games

Download my complete campaign template for projector games

Rejected for DDI – and I feel fine!

Edit: The final, polished version of the adventure can be found at this link.

I decided to submit the third adventure in my Staff of Suha trilogy to Dungeon Magazine for their consideration. The timing was right, after all; the adventure was ready to go at just about the time the submission window would be opening (October 1).

I spent a lot of time in September trying to polish the adventure itself, figuring that if I could attach the finished adventure to the “pitch” email it would help my chances. I ran the adventure four times and had a couple of friends and a couple of readers from my blog look over it and provide really useful feedback.

Since I live in the Mountain time zone, the submission window opened at 10:00 PM Friday night for me (midnight Eastern time). I was finishing my Friday night game that I run via MapTool at the time, after which I read Chris Perkins’ editorial about submitting pitches. I had already written the pitch weeks before, so I went ahead and submitted it exactly one hour after the window opened. The entirety of my email to submissions@wizards.com follows:

Descent Into Darkness – an adventure for 8th-10th level characters – 5,000 – 6,000 words

The powerful wizardess Tallinn seeks adventurers to be teleported into the Underdark bearing a powerful magical artifact, the Staff of Suha. The mission: Find three other artifacts that have been stolen by unknown creatures, likely in an effort to recreate a teleportation device once used by a long-dead drow sorcerer to bring his foul armies to the overworld in conquest. The other three artifacts (Orb of Oradia, Chalice of Chale and Shield of Shalimar) must be recovered or destroyed, and the forces behind their theft must be stopped.

The adventurers discover that the powerful beholder Ergoptis has enslaved drow, diggers (new insectoid monsters), halfling thieves and mindless duergar as soldiers and hunters of artifacts. The party must fight their way through treacherous traps and puzzles to ultimately face Ergoptis and its underlings in a room dominated by a ziggurat, with a magma river crossed by bridges and floating platforms. Can they recover the final artifact and escape or destroy Ergoptis before the one-hour time limit on their teleportation ritual runs out? Or will the beholder simply add the adventurers to its army of enslaved warriors and continue its plans for domination?

Descent Into Darkness includes four new artifacts, an all-new monster (the digger), a find-the-path puzzle with custom runes and an exciting final encounter with an evil beholder.

Link to a PDF of the current draft of the adventure, complete with maps, stat blocks, puzzles, etc: http://dl.dropbox.com/u/6875434/Descent%20into%20Darkness%20Submission.pdf

Michael, the OnlineDM

http://onlinedm.wordpress.com/

That was the pitch. I wondered how long it would take to get a response; they said that they’ll reply to everyone within two months of the close of the submission period, which meant that I could theoretically have to wait until the end of January.

Fortunately, I didn’t have to wait that long. Monday morning I received the following email from Chris Perkins:

Hi Michael,

Thanks for the adventure proposal. The “artifact hunt” story doesn’t really grab me, so I’m going to pass on this one. We see a lot of artifact hunts, and four artifacts seems a bit much (the write-ups for them alone would eat up thousands of words of text). Also, we already have an adventure in the works featuring a beholder villain.

Regards,

Chris Perkins
D&D Senior Producer
Wizards of the Coast LLC

I’ve got to say, I felt pretty good about that. No, they didn’t accept my adventure, but Chris took the time to explain what he didn’t like about the adventure. “Collect the artifacts” doesn’t interest him, and they have another adventure coming with a beholder villain. That’s totally fair.

I came away from this feeling pretty good. The best part was that I got the response quickly, which means that I can release the adventure here on the blog!

The version I actually submitted to Chris is at this link. It’s set up specifically for upper-heroic parties.

However, I also assembled the adventure in a way that can be run with any level in heroic tier (though I feel that the adventure runs best at level 6 or higher). That version can be downloaded here.

I’ll talk more about the adventure itself in a later post, but I wanted to share my thoughts about the process for anyone else who wants to submit an adventure to Dungeon.

First, just focus on the pitch, not the finished product. I’m sure that Chris didn’t even look at the link I sent him, and I don’t blame him for that. He has tons of submissions to go through, and he’s not going to read a sixteen-page PDF for each submission.

Second, be creative. It seems like the key is to pitch something that makes the editor say, “Wow, I’ve never seen anything quite like that before!” The key is novelty, not execution, when it comes to the pitch. I feel like I’ve put together a fun, solid adventure, but the things that make it fun and solid (cool combats, puzzles, magic items, etc.) aren’t the things that make a good pitch. It’s a fairly run-of-the-mill adventure premise, and that’s not going to get it past the initial screen.

Third, do your research. In my case, my adventure was rejected in part because there’s an upcoming adventure with a similar villain, which I couldn’t have known about. But I’m sure that if I had pitched an adventure whose villain was similar to something done in the past few issues of Dungeon, it would have also been rejected. And there’s no excuse for me not knowing that.

Anyway, I’m glad I went through the submission process, and I’m especially glad that Chris handled my rejection letter the way he did – quickly, professionally, and with some helpful feedback. If I get any truly inspired ideas for adventures, I might pitch again. But this process was a good one for me.

MapTool macros: Numbers on tokens – elevation, etc.

Ah, how I love to geek out with new MapTool macros!

Some months ago, I was going to be running a Living Forgotten Realms adventure that involved underwater combat, which meant that elevation could come into play. I wanted to have a visible way of displaying a token’s elevation right on the token itself, so I settled on using some token states that would display a number from 1 to 9 on the upper right corner of the token, representing its elevation.

However, I later realized that having a generic number to stick on a token is a useful thing. For instance, a later battle with a hydra showed me that it would be nice to have an indicator for the number of heads. Furthermore, I’d like to be able to display higher numbers as well, just in case.

Three monsters - one with no elevation, one with elevation 29 and one with elevation 4

Enter the new Elevation macro. First, I should explain that this macro requires you to have a certain set of token states (downloadable as a full set of properties and states here for online use or here for projector use) that include “_0” through “_9” for the ones digit and “0_” through “9_” for the tens digit. You’ll need an Elevation property on your token. And then you’ll need a macro like this one, which you can keep on either the Campaign or Global window.

[h: x=input("NewElevation|0|What is the token's new elevation?")]
[h: abort(x)]

The code above brings up an input window that asks for the new elevation and ends the macro if the user chooses the Cancel option.

[h: SelectedTokens=getSelected()]
[FOREACH(TokenID, SelectedTokens, " "), CODE:

This creates a list of token IDs called SelectedTokens, then starts a loop through each of the tokens, performing the following code on them. Thus, you could set the elevation for a group of three monsters all to the same level at once if you wished.

 {[h: OldElevation=getProperty("Elevation",TokenID)]

Figure out the token’s current Elevation property; assign it to the OldElevation variable.

   [if(NewElevation>99), CODE: {[assert(1==0,add("<b>Error</b>: Elevation cannot be higher than 99"),0)]}; {}]
   [if(NewElevation<0), CODE: {[assert(1==0,add("<b>Error</b>: Elevation cannot be lower than 0"),0)]}; {}]

Give an error message if the user tries to enter a new elevation that’s over 99 or less than zero.

   [h: OldTensDigit=FLOOR(OldElevation/10)]
   [h: OldOnesDigit=OldElevation-10*OldTensDigit]

   [h: NewTensDigit=FLOOR(NewElevation/10)]
   [h: NewOnesDigit=NewElevation-10*NewTensDigit]

Figure out the tens digit and ones digit of both the old and new elevations. I don’t know if MapTool has a modulus function, so I went with an alternative way of getting the ones digit (pretty elegant in the end, I think).

   [h: OldOnesState=add("_", OldOnesDigit)]
   [h: OldTensState=add(OldTensDigit, "_")]

   [h: NewOnesState=add("_", NewOnesDigit)]
   [h: NewTensState=add(NewTensDigit, "_")]

Since the states are called “_1” and “_2” and so on for the ones, and “1_” and “2_” and so on for the tens, I need to concatenate some strings to set up the names of the old and new states (in preparation for removing the old states and adding the new).

   [h: setState(OldOnesState,0,TokenID)]
   [h: setState(OldTensState,0,TokenID)]

   [h: setState(NewOnesState,1,TokenID)]
   [h: setState(NewTensState,1,TokenID)]

And here I actually set those states. The old states get set to zero (turned off) while the new states get set to one (turned on). Thus, if the token is changing from an elevation of 13 to an elevation of 20, I’m turning off “1_” and “_3” and turning on “2_” and “_0”.

   [h: setProperty("Elevation", NewElevation, TokenID)]

Since I’m changing the elevation states, I need to make sure I also change the elevation value on the token itself so that the macro will work again the next time I run it (the new elevation after this go-through will become the old elevation for the next time I run the macro).

   [if(NewElevation<10),CODE:{[h: setState(NewTensState,0,TokenID)]};{}]

This is just for prettiness’ sake; if the new elevation is between 1 and 9, I want to drop the zero from the tens place so the elevation will show up as “7” instead of “07” for instance.

   [if(NewElevation==0),CODE:{
     [h: setState(NewOnesState,0,TokenID)]
     [h: setState(NewTensState,0,TokenID)]};{}]

Further prettiness; If the new elevation is zero, I want no elevation states to be displayed at all, so I now remove the new states that I just added.

    }
   ]

And here I close the FOREACH loop and the Code brackets that I started way up at the top.

This macro is useful any time you want to stick a visible number on a token for whatever reason. Now that I’ve got it working, I’ll be interested to see how often it will come up. My suspicion is that I’ll end up using it a lot.

As always, please let me know what macro questions you have or any requests for new macros. I love this stuff!

Note: All macros were generated with version 1.3.b66 of MapTool.

Campaign template for online use, including this and all of my other macros

Campaign template, formatted for projector use

Campaign properties for online use

Campaign properties for projector use

Download the elevation macro alone

The full elevation macro code:

[h: x=input("NewElevation|0|What is the token's new elevation?")]
[h: abort(x)]

[h: SelectedTokens=getSelected()]
[FOREACH(TokenID, SelectedTokens, " "), CODE:
 {[h: OldElevation=getProperty("Elevation",TokenID)]
   [if(NewElevation>99), CODE: {[assert(1==0,add("<b>Error</b>: Elevation cannot be higher than 99"),0)]}; {}]
   [if(NewElevation<0), CODE: {[assert(1==0,add("<b>Error</b>: Elevation cannot be lower than 0"),0)]}; {}]

   [h: OldTensDigit=FLOOR(OldElevation/10)]
   [h: OldOnesDigit=OldElevation-10*OldTensDigit]

   [h: NewTensDigit=FLOOR(NewElevation/10)]
   [h: NewOnesDigit=NewElevation-10*NewTensDigit]

   [h: OldOnesState=add("_", OldOnesDigit)]
   [h: OldTensState=add(OldTensDigit, "_")]

   [h: NewOnesState=add("_", NewOnesDigit)]
   [h: NewTensState=add(NewTensDigit, "_")]

   [h: setState(OldOnesState,0,TokenID)]
   [h: setState(OldTensState,0,TokenID)]

   [h: setState(NewOnesState,1,TokenID)]
   [h: setState(NewTensState,1,TokenID)]

   [h: setProperty("Elevation", NewElevation, TokenID)]

   [if(NewElevation<10),CODE:{[h: setState(NewTensState,0,TokenID)]};{}]

   [if(NewElevation==0),CODE:{
     [h: setState(NewOnesState,0,TokenID)]
     [h: setState(NewTensState,0,TokenID)]};{}]
    }
   ]

Running online D&D: Weekly prep

I’ve talked a fair amount on my blog about macros that I’ve programmed in MapTool for my online games and recaps of adventures that I’ve run, but I realized that I haven’t spent any time talking about the prep process. Preparing to run a game online has a lot in common with an in-person game with vinyl mats and minis, but it definitely has its differences.

1 week before the game

I figure out what I’m going to be running. For my longest-running online game, this is easy; we’re running EN World’s War of the Burning Sky campaign and have been for over a year. I do still need to make sure I’ve read far enough ahead in the campaign to know what’s coming in the broad sense, but I try to be good about staying ahead of things there.

For my other online games, this might mean picking out a one-shot game (like a Living Forgotten Realms adventure) or actually writing my own adventures (a topic for another blog post).

This is also the time that I reach out to the online players about any changes they need to make to their characters. For instance, if they’ve leveled up after the last session, I remind them to tell me what choices they’re making for their characters. This is a difference between an online game and an in-person game; online, I have to maintain the tokens for the PCs and add new powers, adjust stats, etc. I also talk about magic items that the party acquired in the previous session and see which PC is going to be using them (so I can update their tokens).

3 days before the game

I send out an email to the group, announcing that there will be a session at our usual time (6:00 PM Mountain Time on Friday night for me and the person in South Dakota; 5:00 PM for the person in California; 7:00 PM for the people in Indiana and Texas, 8:00 PM for the people in New Jersey and Florida, and 9:00 AM Saturday for the person in Japan), asking who will be able to attend. I usually get a couple of responses right away and the rest trickle in over the next couple of days. Sometimes I’ll get a “maybe” (there’s a possible schedule conflict, but they might be able to come – this is usually a “no” in the end). I have a total of seven players, and we usually have 4-5 show up each week. One of the seven is almost never there, and four are almost always there; the other two are there most of the time, but not all of the time. This works for us, though I know some DMs don’t like it if players are absent irregularly. This is why I have seven players! We can still game even if three people are unavailable.

1-2 days before the game

I do my actual prep work (sometimes I get this done earlier, of course). This involves a few things:

  • Updating PC stats if the players have sent them to me after a level-up
  • Updating PC treasure if the players have decided on what they’re using
  • Setting up the maps for the next few encounters (easy for War of the Burning Sky, since decent JPG versions of the maps are available)
  • Building monsters for the next few encounters using my handy-dandy monster construction macro

For some reason, I used to procrastinate more about the PC stuff than the map and monster stuff. When the PCs hit paragon tier, I actually canceled a session so I could use that four-hour time slot to work on their PC tokens. It’s gotten better since I’ve changed my PC properties to be easier to level up (defenses now scale automatically with level, for instance), but there was a time when I almost wanted to stop running online games just because of the extra layer of work on the DM to update PC tokens. It’s better now, though.

The new monster macro has made building the monsters way easier and actually more fun. I also enjoy the process of using TokenTool to create cool-looking monster tokens from images I find online. I’m sure lots of these images are copyrighted and such, but I’m only using them in my own game (this is part of the reason I don’t distribute lots of monster tokens on my blog – well, that and laziness).

The day of the game

Since our game starts at 6:00 PM my time, I go to work early so I can leave at 4:00 PM. It only takes me 15 minutes to get home, at which point I’ll chat with my wife briefly and help take care of household tasks (feed the cats, figure out dinner). This usually leaves me at the computer by around 5:00, giving me time for last-minute prep. If there are any monsters I haven’t done yet, I’ll try to put those together quickly. If I already have a good image for the monster, it tends to take about 5 minutes per monster type to assemble.

If all goes well, I like to spend the time from 5:30 onward re-reading the material I’ll be running that evening. War of the Burning Sky is a very story-heavy adventure, and I want to make sure I understand the various NPCs and the branching points of the tale so that it all makes sense during the game.

At 5:45, I start up the MapTool server so that my players can connect. It’s not at all unusual for one or two people to be ready to go right at that time, and we might chat a bit in the text window of MapTool until start time, or they might say, “Hi, I’m here, but I’m going to be busy with something else for the next few minutes.” I also might say, “Okay, the server is up, but I’m still preppping! Please talk amongst yourselves. I’ll give you a topic: A half-elf is neither a halfling nor an elf. Discuss.”

At 6:00, assuming we have at least 3 players on MapTool, I’ll start the Skype audio call so we can talk to each other… and away we go!

Game on!

After that, we play D&D for four hours. Honestly, the online experience is darn near as good as the in-person experience for me. We still get to know each other out-of-game and chat as friends. Role-playing still happens. Combat is still exciting – and pretty quick, too, thanks to the software handling a lot of the math. It’s a ton of fun, and while I also enjoy in-person games, my online game is my longest-running campaign by far.

I’ll talk in later posts about the process of running a session, but I hope this window into the online game prep process helps to show you what it’s like. Give online D&D a try sometime – it’s a ton of fun!

Guest Post from Paul Baalham: MapTool ongoing damage tracking macro

Editor’s note from OnlineDM: Today we are lucky to have another guest post, this one from Paul Baalham (@paulbaalham on Twitter; you can also find him at Daily Encounter).

Tracking ongoing damage and conditions with MapTool for 4E

As a DM that wants to use MapTool to handle all the boring stuff of D&D fights, to leave the players and me more tim for the fun stuff, I realised very early on that I wanted to create a system that would track ongoing damage and conditions so that we wouldn’t forget about the ongoing damage or that the slowed condition actually ended on the PC’s last turn. I managed to get the ongoing damage tracked quite easily so here is what I have done. Could it be improved? Almost certainly. If you can improve it then PLEASE let me know in the comments.

Campaign Properties

The code in this post require the following properties for the tokens that will be using it (i.e. players and monsters).

Acid:0
Cold:0
Fire:0
Force:0
Lightning:0
Necrotic:0
Poison:0
Psychic:0
Radiant:0
Thunder:0
Untyped:0
SEAcid:0
SECold:0
SEFire:0
SEForce:0
SELightning:0
SENecrotic:0
SEPoison:0
SEPsychic:0
SERadiant:0
SEThunder:0
SEUntyped:0
IsWarden:0

The SE variables are to help determine whether there is a Save Ends condition. I think there is probably a way of eliminating these, but I haven’t thought of a way yet (it works currently so I don’t want to break it!) The ISWarden may look out of place, but as Wardens can save against ongoing damage at the start of their turn, this variable helps in keeping track of the initiative.

The “Place Ongoing Damage” Button

I created a button for placing ongoing damage to tokens. This was situated on my Campaign macros window, but where you put it is up to you,

First of all, in the States section of the Campaign Properties the following states should be present:

Acid
Cold
Fire
Force
Lightning
Necrotic
Poison
Psychic
Radiant
Thunder
Untyped

Each one of these states should be in the Group called “Damage”.

This allows us to collect together all of the ongoing damage types like this:

[h: dmgList = getTokenStates(",","Damage")]

We then need to get a list of all of the tokens that are on the map:

[h: tokenList=getExposedTokenNames()]
[h: imgList = tokenList]
[h: Num = listCount(imgList)]

We need to create a list of token names and create a list of images to display.

[h,COUNT(Num),CODE:
{
  [h:tokenName=listGet(imgList,roll.count)]
  [h,token(tokenName): image=getTokenImage()]
  [h:imgList=listReplace(imgList,roll.count,tokenName+" "+image)]
}]

Next we display a pop up window that shows a list of targets (including images) as well as a list of the types of damage. Finally the value of the ongoing damage needs to be typed in by the DM.

[h:status=input(
"Target|"+imgList+"|Select Target|LIST|SELECT=0 ICON=TRUE ICONSIZE=30",
"damageType|"+dmgList+"|Select Type of Damage|LIST|SELECT=0 VALUE=STRING",
"amount| |Enter amount of damage"
)]
[h:abort(status)]

We now know the name of the target so we can switch the focus to that token:

[h:targetName = listGet(tokenList,Target)]
[h:switchToken(targetName)]

The following looks at what type of damage it was, sets the value of the appropriate variable and then creates a string to be dsiplayed at the end. This is the bit of code I think is the most likely that someone could improve upon.

[h,switch(damageType),code:
  case "Acid": {
    [h: Acid=amount]
    [h: SEAcid=1]
    [h: stringToShow= targetName+ " has ongoing Acid damage"]
  };
  case "Cold": {
    [h: Cold=amount]
    [h: SECold=1]
    [h: stringToShow= targetName+ " has ongoing Cold damage"]
  };
  case "Fire": {
    [h: Fire=amount]
    [h: SEFire=1]
    [h: stringToShow= targetName+ " has ongoing Fire damage"]
  };
  case "Force": {
    [h: Force=amount]
    [h: SEForce=1]
    [h: stringToShow= targetName+ " has ongoing Force damage"]
  };
  case "Lightning": {
    [h: Lightning=amount]
    [h: SELightning=1]
    [h: stringToShow= targetName+ " has ongoing Lightning damage"]
  };
  case "Thunder": {
    [h: Thunder=amount]
    [h: SEThunder=1]
    [h: stringToShow= targetName+ " has ongoing Thunder damage"]
  };
  case "Necrotic": {
    [h: Necrotic=amount]
    [h: SENecrotic=1]
    [h: stringToShow= targetName+ " has ongoing Necrotic damage"]
  };
  case "Psychic": {
    [h: Psychic=amount]
    [h: SEPsychic=1]
    [h: stringToShow= targetName+ " has ongoing Psychic damage"]
  };
  case "Poison": {
    [h: Poison=amount]
    [h: SEPoison=1]
    [h: stringToShow= targetName+ " has ongoing Poison damage"]
};
  case "Radiant": {
    [h: Radiant=amount]
    [h: SERadiant=1]
    [h: stringToShow= targetName+ " has ongoing Radiant damage"]
  };
  case "Untyped": {
    [h: Untyped=amount]
    [h: SEUntyped=1]
    [h: stringToShow= targetName+ " has ongoing damage (untyped)"]
  }
]

Almost finished! We need to put the damage on the token.

[h:Condition=damageType]
[h:setState(Condition,1)]

And finally show the string that we formatted earlier that tells everyone who has been tagged with ongoing damage, the type and how much.

[r: stringToShow]

Now we have a way of placing the ongoing damage on a token, we need a way of automating the subtraction of the damage from tokens at the start of their turn and reminding them to save at the end of their turn.

The “Next Initiative” Button

I created a button that I placed on the Campaign group called Next Initiative which passes the initiative to the next person on the list. But before it does this it checks to see if the current token has any save ends conditions on it (I have only pasted the ongoing damage here as conditions will be in another post).

First of all, we need to determine who the current token is and switch the focus to that token:

[h: id = getInitiativeToken()]
[h: switchToken(id)]
[h: targetname=getName(id)]

Next we need to see if the token has ongoing damage it needs to save against. It will then ask if the token has saved against it. The DM will see a popup window asking if the player saved against the condition. The player should still be able to roll for the save while the pop up is on the DM’s screen.

[h:saveList=""]
[h,if(SEAcid), code: {
  [h:stringToShow="Did " + targetname + " Save against ongoing Acid damage? (1=yes, 0=no)"]
  [h:status=input("hasSaved|0|"+stringToShow)]
  [h:abort(status)]
  [h,if(hasSaved), code: {
    [h:SEAcid=0]
    [h:Acid=0]
    [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Acid damage! :D"]
    [h:state.Acid=0]
  };
  {
    [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Acid damage! :("]
  }]
}]

[h,if(SECold), code: {
  [h:stringToShow="Did " + targetname + " Save against ongoing Cold damage? (1=yes, 0=no)"]
  [h:status=input("hasSaved|0|"+stringToShow)]
  [h:abort(status)]
  [h,if(hasSaved), code: {
    [h:SECold=0]
    [h:Cold=0]
    [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Cold damage! :D"]
    [h:state.Cold=0]
  };
  {
    [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Cold damage! :("]
  }]
}]
[h,if(SEFire), code: {
  [h:stringToShow="Did " + targetname + " Save against ongoing Fire damage? (1=yes, 0=no)"]
  [h:status=input("hasSaved|0|"+stringToShow)]
  [h:abort(status)]
  [h,if(hasSaved), code: {
    [h:SEFire=0]
    [h:Fire=0]
    [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Fire damage! :D"]
    [h:state.Fire=0]
  };
  {
    [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Fire damage! :("]
  }]
}]
[h,if(SEForce), code: {
  [h:stringToShow="Did " + targetname + " Save against ongoing Force damage? (1=yes, 0=no)"]
  [h:status=input("hasSaved|0|"+stringToShow)]
  [h:abort(status)]
  [h,if(hasSaved), code: {
    [h:SEForce=0]
    [h:Force=0]
    [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Force damage! :D"]
    [h:state.Force=0]
  };
  {
    [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Force damage! :("]
  }]
}]
[h,if(SELightning), code: {
  [h:stringToShow="Did " + targetname + " Save against ongoing Lightning damage? (1=yes, 0=no)"]
  [h:status=input("hasSaved|0|"+stringToShow)]
  [h:abort(status)]
  [h,if(hasSaved), code: {
    [h:SELightning=0]
    [h:Lightning=0]
    [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Lightning damage! :D"]
    [h:state.Lightning=0]
  };
  {
    [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Lightning damage! :("]
  }]
}]
[h,if(SENecrotic), code: {
  [h:stringToShow="Did " + targetname + " Save against ongoing Necrotic damage? (1=yes, 0=no)"]
  [h:status=input("hasSaved|0|"+stringToShow)]
  [h:abort(status)]
  [h,if(hasSaved), code: {
    [h:SENecrotic=0]
    [h:Necrotic=0]
    [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Necrotic damage! :D"]
    [h:state.Necrotic=0]
  };
  {
    [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Necrotic damage! :("]
  }]
}]
[h,if(SEPoison), code: {
  [h:stringToShow="Did " + targetname + " Save against ongoing Poison damage? (1=yes, 0=no)"]
  [h:status=input("hasSaved|0|"+stringToShow)]
  [h:abort(status)]
  [h,if(hasSaved), code: {
    [h:SEPoison=0]
    [h:Poison=0]
    [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Poison damage! :D"]
    [h:state.Poison=0]
  };
  {
    [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Poison damage! :("]
  }]
}]
[h,if(SEPsychic), code: {
  [h:stringToShow="Did " + targetname + " Save against ongoing Psychic damage? (1=yes, 0=no)"]
  [h:status=input("hasSaved|0|"+stringToShow)]
  [h:abort(status)]
  [h,if(hasSaved), code: {
    [h:SEPsychic=0]
    [h:Psychic=0]
    [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Psychic damage! :D"]
    [h:state.Psychic=0]
  };
  {
    [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Psychic damage! :("]
  }]
}]
[h,if(SERadiant), code: {
  [h:stringToShow="Did " + targetname + " Save against ongoing Radiant damage? (1=yes, 0=no)"]
  [h:status=input("hasSaved|0|"+stringToShow)]
  [h:abort(status)]
  [h,if(hasSaved), code: {
    [h:SERadiant=0]
    [h:Radiant=0]
    [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Radiant damage! :D"]
    [h:state.Radiant=0]
  };
  {
    [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Radiant damage! :("]
  }]
}]
[h,if(SEThunder), code: {
  [h:stringToShow="Did " + targetname + " Save against ongoing Thunder damage? (1=yes, 0=no)"]
  [h:status=input("hasSaved|0|"+stringToShow)]
  [h:abort(status)]
  [h,if(hasSaved), code: {
    [h:SEThunder=0]
    [h:Thunder=0]
    [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Thunder damage! :D"]
    [h:state.Thunder=0]
  };
  {
    [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Thunder damage! :("]
  }]
}]
[h,if(SEUntyped), code: {
  [h:stringToShow="Did " + targetname + " Save against ongoing Untyped damage? (1=yes, 0=no)"]
  [h:status=input("hasSaved|0|"+stringToShow)]
  [h:abort(status)]
  [h,if(hasSaved), code: {
    [h:SEUntyped=0]
    [h:Untyped=0]
    [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Untyped damage! :D"]
    [h:state.Untyped=0]
  };
  {
    [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Untyped damage! :("]
  }]
}]

[h:stringToList(saveList, " ")]
[h:number=listCount(saveList)]
[r,if(number>0),code:{
  [r,foreach(var,saveList),code:{
    [r:var]
    <br>
  }]
}]
<br>

Pass the initiative onto the next token.

[h: nextInitiative()]

And here is where it starts to get a bit messy. My wife plays a Warden in the game. Wardens get to save against conditions at the START of their turn.

Get the token that now has initiative and switch the focus to them.

[h: id = getInitiativeToken()]
[h: switchToken(id)]

If they are a Warden then repeat the code from up above:

[h,if(isWarden==1),code: {
  [h:saveList=""]
  [h,if(SEAcid), code: {
    [h:stringToShow="Did " + targetname + " Save against ongoing Acid damage? (1=yes, 0=no)"]
    [h:status=input("hasSaved|0|"+stringToShow)]
    [h:abort(status)]
    [h,if(hasSaved), code: {
      [h:SEAcid=0]
      [h:Acid=0]
      [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Acid damage! :D"]
      [h:state.Acid=0]
    };
    {
      [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Acid damage! :("]
    }]
  }]
  [h,if(SECold), code: {
    [h:stringToShow="Did " + targetname + " Save against ongoing Cold damage? (1=yes, 0=no)"]
    [h:status=input("hasSaved|0|"+stringToShow)]
    [h:abort(status)]
    [h,if(hasSaved), code: {
      [h:SECold=0]
      [h:Cold=0]
      [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Cold damage! :D"]
      [h:state.Cold=0]
    };
    {
      [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Cold damage! :("]
    }]
  }]
  [h,if(SEFire), code: {
    [h:stringToShow="Did " + targetname + " Save against ongoing Fire damage? (1=yes, 0=no)"]
    [h:status=input("hasSaved|0|"+stringToShow)]
    [h:abort(status)]
    [h,if(hasSaved), code: {
      [h:SEFire=0]
      [h:Fire=0]
      [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Fire damage! :D"]
      [h:state.Fire=0]
    };
    {
      [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Fire damage! :("]
    }]
  }]
  [h,if(SEForce), code: {
    [h:stringToShow="Did " + targetname + " Save against ongoing Force damage? (1=yes, 0=no)"]
    [h:status=input("hasSaved|0|"+stringToShow)]
    [h:abort(status)]
    [h,if(hasSaved), code: {
      [h:SEForce=0]
      [h:Force=0]
      [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Force damage! :D"]
      [h:state.Force=0]
    };
    {
      [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Force damage! :("]
    }]
  }]
  [h,if(SELightning), code: {
    [h:stringToShow="Did " + targetname + " Save against ongoing Lightning damage? (1=yes, 0=no)"]
    [h:status=input("hasSaved|0|"+stringToShow)]
    [h:abort(status)]
    [h,if(hasSaved), code: {
      [h:SELightning=0]
      [h:Lightning=0]
      [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Lightning damage! :D"]
      [h:state.Lightning=0]
    };
    {
      [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Lightning damage! :("]
    }]
  }]
  [h,if(SENecrotic), code: {
    [h:stringToShow="Did " + targetname + " Save against ongoing Necrotic damage? (1=yes, 0=no)"]
    [h:status=input("hasSaved|0|"+stringToShow)]
    [h:abort(status)]
    [h,if(hasSaved), code: {
      [h:SENecrotic=0]
      [h:Necrotic=0]
      [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Necrotic damage! :D"]
      [h:state.Necrotic=0]
    };
    {
      [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Necrotic damage! :("]
    }]
  }]
  [h,if(SEPoison), code: {
    [h:stringToShow="Did " + targetname + " Save against ongoing Poison damage? (1=yes, 0=no)"]
    [h:status=input("hasSaved|0|"+stringToShow)]
    [h:abort(status)]
    [h,if(hasSaved), code: {
      [h:SEPoison=0]
      [h:Poison=0]
      [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Poison damage! :D"]
      [h:state.Poison=0]
    };
    {
      [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Poison damage! :("]
    }]
  }]
  [h,if(SEPsychic), code: {
    [h:stringToShow="Did " + targetname + " Save against ongoing Psychic damage? (1=yes, 0=no)"]
    [h:status=input("hasSaved|0|"+stringToShow)]
    [h:abort(status)]
    [h,if(hasSaved), code: {
      [h:SEPsychic=0]
      [h:Psychic=0]
      [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Psychic damage! :D"]
      [h:state.Psychic=0]
    };
    {
      [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Psychic damage! :("]
    }]
  }]
  [h,if(SERadiant), code: {
    [h:stringToShow="Did " + targetname + " Save against ongoing Radiant damage? (1=yes, 0=no)"]
    [h:status=input("hasSaved|0|"+stringToShow)]
    [h:abort(status)]
    [h,if(hasSaved), code: {
      [h:SERadiant=0]
      [h:Radiant=0]
      [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Radiant damage! :D"]
      [h:state.Radiant=0]
    };
    {
      [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Radiant damage! :("]
    }]
  }]
  [h,if(SEThunder), code: {
    [h:stringToShow="Did " + targetname + " Save against ongoing Thunder damage? (1=yes, 0=no)"]
    [h:status=input("hasSaved|0|"+stringToShow)]
    [h:abort(status)]
    [h,if(hasSaved), code: {
      [h:SEThunder=0]
      [h:Thunder=0]
      [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Thunder damage! :D"]
      [h:state.Thunder=0]
    };
    {
      [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Thunder damage! :("]
    }]
  }]
  [h,if(SEUntyped), code: {
    [h:stringToShow="Did " + targetname + " Save against ongoing Untyped damage? (1=yes, 0=no)"]
    [h:status=input("hasSaved|0|"+stringToShow)]
    [h:abort(status)]
    [h,if(hasSaved), code: {
      [h:SEUntyped=0]
      [h:Untyped=0]
      [h:saveList=saveList+" ,"+targetname + " has saved against the ongoing Untyped damage! :D"]
      [h:state.Untyped=0]
    };
    {
      [h:saveList=saveList+" ,"+targetname + " did not save against the ongoing Untyped damage! :("]
    }]
  }]
}]

[h:stringToList(saveList, " ")]
[h:number=listCount(saveList)]
[r,if(number>0),code:{
  [r,foreach(var,saveList),code:{
    [r:var]
    <br>
  }]
}]

Next. we display the name of who has initiative and display the current conditions effecting them.

[r: getName(id) + " has Initiative"]
[r:strlist = "and currently has"]

The next line just sees whether there is any ongoing damage at all (this could probably be used further up, but I haven’t done this yet).

[h:OD=Acid+Cold+Fire+Force+Lightning+Necrotic+Poison+Psychic+Radiant+Thunder+Untyped]

If there is ongoing damage then cycle through the damage types and subtract the value from the token’s HP.

[h,if(OD>0),code:{
  [h,if(Acid>0):strlist=strlist+" ,"+ string(Acid)+" Acid damage"]
  [h,if(Cold>0):strlist=strlist+" ,"+ string(Cold)+" Cold damage"]
  [h,if(Fire>0):strlist=strlist+" ,"+ string(Fire)+" Fire damage"]
  [h,if(Force>0):strlist=strlist+" ,"+ string(Force)+" Force damage"]
  [h,if(Lightning>0):strlist=strlist+" ,"+ string(Lightning)+" Lightning damage"]
  [h,if(Necrotic>0):strlist=strlist+" ,"+ string(Necrotic)+" Necrotic damage"]
  [h,if(Poison>0):strlist=strlist + " ," + string(Poison)+" Poison damage"]
  [h,if(Psychic>0):strlist=strlist+" ,"+ string(Psychic)+" Psychic damage"]
  [h,if(Radiant>0):strlist=strlist+" ,"+ string(Radiant)+" Radiant damage"]
  [h,if(Thunder>0):strlist=strlist+" ,"+ string(Thunder)+" Thunder damage"]
  [h,if(Untyped>0):strlist=strlist+" ,"+ string(Untyped)+" Untyped damage"]
  [h:HP=HP-Cold]
  [h:HP=HP-Fire]
  [h:HP=HP-Force]
  [h:HP=HP-Lightning]
  [h:HP=HP-Necrotic]
  [h:HP=HP-Poison]
  [h:HP=HP-Psychic]
  [h:HP=HP-Radiant]
  [h:HP=HP-Thunder]
  [h:HP=HP-Untyped]
  [h:strlist=strlist + ", and now has " + HP + " HP"]
  [state.Dying = 1 - max(0,min(1,HP))]
  [state.Bloodied = 1 - max(0, min(1,HP - Bloodied))]
  [setBar("Health", HP/MaxHP)]
}]

Finally display the ongoing damages that the token is suffering from.

[h:stringToList(strlist, " ")]
[h:number=listCount(strlist)]
[r,if(number>1),code:{
  [r,foreach(var,strlist),code:{
    [r:var]
    <br>
  }]
}]

I hope someone finds this useful. I am not a software programmer by trade (although I do have to occasionally write code), so I am sure this code could be improved. It would be awesome if someone took this and made it better and allowed OnlineDM to post it on his site.

How should a DM handle a monster who’s marked?

Most of my RPG experience so far has been with Dungeons and Dragons 4th Edition, and I believe 4e was the first edition to introduce the concept of “marking” a monster. Defenders all have some type of marking mechanic, in which a marked monster takes a -2 penalty to attack anyone other than the defender who has marked it (unless it’s part of an attack that includes multiple PCs, and the defender is one of them).

Defenders also have some type of “punishment” mechanic attached to the mark, which will have an additional negative effect on the monster if it “breaks” the mark by attacking someone other than the defender. Sometimes the punishment is built into the marking ability itself; sometimes it’s a separate ability that says “When a creature marked by you is naughty, you get to beat it up.”

The usefulness of these marking and punishment mechanics depends to a large degree on the dungeon master and how the DM plays the monsters. There are two extremes the DM could follow (as well as points between): Ignore the mark, and always obey the mark.

Mark? What mark?

On this end of the spectrum, the DM has the monsters act as if they’re completely oblivious to the existence of a mark. Maybe they’ll attack the defender, or maybe they’ll attack someone else. The mark has no bearing on their actions. It’s a pretty stupid way for a monster to act, especially after it gets punished a few times, but hey, some monsters are stupid.

You must obey!

This other end of the “mark obedience spectrum” is where I fell when I first started DMing. In this mindset, the monster knows that it’s marked and that bad things will happen if it attacks someone other than the defender without also attacking the defender, so it attacks the defender. In this way, the defender is doing its job of keeping the scary monsters from attacking the rest of the party. Yay, right?

Don’t ALWAYS obey

Well, no. It was an article on Neuroglyph Games that got me thinking about this a few months ago. The author of the article ranked the Battlemind’s punishment mechanic as being outstanding compared to other defenders. The Battlemind, as you may know, has the ability to punish an adjacent enemy that deals damage to the Battlemind’s ally by dealing an equal amount of damage to that enemy. You hit my friend; I hit you. Bam.

Now, it’s true that this punishment mechanic can deal a whole lot of damage to a monster, especially compared to some of the other punishment mechanics out there. But the problem for me as a DM is that I had been running a game for several levels where the defender was a Battlemind, and her punishment mechanic never, ever did anything.

Why not? Well, she had to be adjacent to the monster in order to punish it. And if she was adjacent, the monster would obey the mark and attack her! The only time the monster ever broke the mark was if the Battlemind wasn’t adjacent, in which case there was no punishment involved.

It’s fun to disobey!

Defenders feel good about themselves when they protect their squishy allies, true. But they also feel good about themselves when they get to beat the crap out of a monster for daring to go after their allies. If the defender’s punishment mechanic never triggers, the defender’s player is having less fun than they could have. And I do believe that the DM should try to help the players have as much fun as possible.

The evolved approach: Role-play the monsters

So what’s the right answer? Remember that this is a role-playing game, and role-play the monsters!

A mindless zombie or single-minded beast is likely to act stupidly or instinctively. This might mean attacking the closest PC or attacking the PC that hurt them the worst or going after the PC who hit it most recently. This monster will fall on the “ignore the mark” end of the spectrum to start with. However, after it gets punished once (or twice, in the case of a really dumb bad guy) it will probably realize that ignoring the defender hurts, and it will start focusing on the defender instead.

Most monsters won’t know exactly how a defender’s punishment mechanic work, and I run it this way even if the rules as written technically say that the monster DOES know (as in the case of a mark power where the punishment is part of that same power). Most monsters at my table will say, “Hm, that fighter is calling me out. But I don’t feel like trying to chew through that armor, so I’m going to eat this tasty-looking wizard instead. OUCH! The fighter hit me when I tried to eat the wizard! Well that does it – you’re gonna get it now, armor boy!” They learn what the punishment mechanic does after it hits them (or one of their nearby allies).

Now, some monsters will be intelligent and may even have experience with battling adventurers. If you have a master tactician going against the players, it can be reasonable for that tactician to instruct its allies to avoid breaking the defender’s mark unless it’s really worth it. If that’s the case, it’s important for the DM to role-play this out at the table. “Ah, I see that your pathetic warden has tried to convince my hell hound to attack it instead of the dazed cleric. Do not be fooled, my minion! Destroy that horrid Pelor-worshipper, no matter the cost!”

The bottom line

Throw the defender a bone now and then by letting monsters discover what the defender’s punishment mechanic can do. Allow the monsters to learn from experience. And if the monster is really smart, have it show the players how smart it is by only breaking marks when it’s advantageous to do so – and make it clear that this is happening because the ENEMY is a tactical genius, not because the DM is.

Being a part of the online D&D community

I’ve been writing about D&D since April 2010, and I’m quite happy with my blog. Not a ton of people read it, but some do, and that’s enough for me. I blog for myself, not to please others, and when I look back at what I’ve written and ahead at what I’m planning to write, I feel proud.

However, I’m starting to become more aware of the broader RPG community online… and the fact that I’m not really a part of it. At GenCon this year I wanted to meet several of the people whose D&D blogs I read or whose podcasts I listen to, and I was happy to meet them. It was clear, though, that none of them had the foggiest clue who I was after I introduced myself.

Now, if I were talking about meeting celebrities in film or music or something like that, I would expect that the people whose work I follow wouldn’t know who I was. But in the RPG blogging community, well, we’re a smaller group. I thought of myself as being part of that community, but I later realized that I’m on the outside fringes.

It’s a bit of a strange feeling. The feeling is magnified now that I’m on Twitter (OnlineDM1, in case you were wondering). I see conversations go back and forth among RPG bloggers, and I occasionally toss in a comment here or there, but I realize that I’m an outsider in that community.

Ultimately, if I want to be a part of this community, it’s up to me. I’ve reached out to a fellow blogger whose work I admire to help out with an adventure he’s writing. I think that’s the kind of thing I need to do if I’m going to be anything other than a fringe member of the community. I need to make myself available to help others. People don’t notice me just because I write and am on the RPG Bloggers Network and the RPG Blog Alliance. To be a part of the community, I need to offer something to that community. They’re not going to just invite me in.

I guess my goal is to look back on this post a year from now and laugh. “It’s so funny to read how I used to feel like an outsider in the RPG blogging community! Ah, how times have changed.” Making that happen is up to me. I’m always open to advice, though!