MapTool Macros

Last Updated: January 12, 2020

MapTool is a free virtual tabletop program that uses Swing Components from JIDE. It replaces all of the pens, paper, battle mats and dice you'd normally need to get through a roleplaying game. In their place, you're provided with a wonderfully intuitive series of built-in functions like Initiative, Chat and Token Management. Plus, you can use HTML syntax through the chat window, allowing everything from highlighting and picture posting, to complex character sheet generation. And, best of all, you can use it as either a stand-alone product on a single screen (like a projector or flat-screen television), or play over the net with people on the other side of the world, each with their own unique view of the action.

One of my favorite things about it, though, aside from being able to keep track of everything on tokens, and having individual fog-of-war and vision blocking layers for my players, is being able to code my own macros. Below, you'll find a few of my favorite macros that can be used without altering the campaign properties.

Tavern Generator

A relatively simple tavern generator that outputs with a name, menu, choice of drinks, and price list. The location names used are from a D&D 3.5ed port of my Wyrmsele campaign setting, and in the case that a wine is selected, it notes whether it's a white (W) or a red (R) so there's no confusion. Its output looks like this:

The tavern is called the Dirty Dwarf. The house dish is Roasted Veal, and it sells for 5sp. This week's special is Seared Darkmantle for 10sp. Their best beer is Strong Porter from Splendarrcaurak for 4cp per mug, or 64sp per hand keg. They also have a Bittersweet cider from Silverwitch for 8cp per mug, or 128sp per hand keg. Their best wine is Gewurztraminer (W) from Sammanfearn for 5cp per mug, or 80sp per hand keg.

[H: prefix = "Angry,Bloody,Dirty,Drunken,Churlish,Jolly,Mewling,Rusty,Skinny,Bronze,Silver,Gold"]
[H: PrefixChoice = listGet(prefix,max(0,1d10-1))]

[H: suffix = "Human,Elf,Dwarf,Gnome,Orc,Dragon,Horse,Dog,Cat,Bat,Rat,Unicorn,Adept,Aristocrat,Cleric,Commoner,Expert,Rogue,Warrior,Wizard,Wench,Hell-spawn"]
[H: SuffixChoice = listGet(suffix,max(0,1d22-1))]

[H: cookprefix = "Baked,Roasted,Grilled,Braised,Broiled,Sauteed,Seared,Slow-Roasted,Smoked,Spit-Roasted,Deep-fried,Batterred and Fried,Boiled,Charbroiled,Poached,Steamed,Toasted,Charred"]
[H: CookprefixChoice = listGet(cookprefix,max(0,1d18-1))]

[H: main =  "Root Vegetables,Beef,Veal,Pork,Lamb,Mutton,Goat,Chicken,Duck,Turkey,Goose,Pheasant,Squab,Cod,Herring,Salmon,Trout,Squid,Octopus,Seal,Whale,Crab,Lobster,Shellfish"]
[H: MainChoice = listGet(main,max(0,1d24-1))]

[H: exotic =  "Dire Rat,Monstrous Centipede,Darkmantle,Dire Bat,Leopard,Owlbear,Cockatrice,Fiendish Ape,Grick,HellHound"]
[H: ExoticChoice = listGet(exotic,max(0,1d10-1))]

[H: beerprefix =  "Amber,Blonde,Brown,Cream,Dark,Fruit,Golden,Honey,Pale,Light,Pilsner,Red,Strong,Wheat"]
[H: BeerprefixChoice = listGet(beerprefix,max(0,1d14-1))]

[H: beer =  "Ale,Lager,Stout,Porter,Malt"]
[H: BeerChoice = listGet(beer,max(0,1d5-1))]

[H: cider =  "Bittersweet,Sweet,Bittersharp,Sharp"]
[H: CiderChoice = listGet(cider,max(0,1d4-1))]

[H: wine =  "Reisling (W),Gewurztraminer (W),Chardonnay (W),Sauvignon Blanc (W),Syrah (R),Merlot (R),Cabernet Sauvignon (R),Pinot Noir (R),Clarry,Mead,White Port,Tawny Port,Ruby Port,Vintage Port"]
[H: WineChoice = listGet(wine,max(0,1d14-1))]

[H: location =  "Lustan,Silverwitch,Hiswetaure,Verthaven,Varnamar,Findarlevasst,Splendarrcaurak,Sammanfearn,Westhollow,Windsedge,Norcastle,Newborough,Woodfell Hollow,Mornacama Taure"]
[H: LocationChoice = listGet(location,max(0,1d14-1))]

[H: location1 =  "Lustan,Silverwitch,Hiswetaure,Verthaven,Varnamar,Findarlevasst,Splendarrcaurak,Sammanfearn,Westhollow,Windsedge,Norcastle,Newborough,Woodfell Hollow,Mornacama Taure"]
[H: LocationChoice1 = listGet(location1,max(0,1d14-1))]

[H: location2 =  "Lustan,Silverwitch,Hiswetaure,Verthaven,Varnamar,Findarlevasst,Splendarrcaurak,Sammanfearn,Westhollow,Windsedge,Norcastle,Newborough,Woodfell Hollow,Mornacama Taure"]
[H: LocationChoice2 = listGet(location2,max(0,1d14-1))]

[H: price = 1d4+2]
[H: exoticprice = price*2]
[H: mug = 1d5+3]
[H: handkeg = mug*16]
[H: mug1 = 1d5+3]
[H: handkeg1 = mug1*16]
[H: mug2 = 1d5+3]
[H: handkeg2 = mug2*16]

[R: strformat("The tavern is called the %{PrefixChoice} %{SuffixChoice}. The house dish is %{CookprefixChoice} %{MainChoice}, and it sells for %{price}sp. This week's special is %{CookprefixChoice} %{ExoticChoice} for %{exoticprice}sp. Their best beer is %{BeerprefixChoice} %{BeerChoice} from %{LocationChoice} for %{mug}cp per mug, or %{handkeg}sp per hand keg. They also have a %{CiderChoice} cider from %{LocationChoice1} for %{mug1}cp per mug, or %{handkeg1}sp per hand keg. Their best wine is %{WineChoice} from %{LocationChoice2} for %{mug2}cp per mug, or %{handkeg2}sp per hand keg.")] 

Old English Village Generator

A basic village generator that saves time and effort by making unnamed, random villages into something a bit more useful. It outputs with a village descriptor, a village name broken down with its meaning, a population count, its most notable trade good, and the DC of its main trade good categories. The output looks like this:

The tidy village of (Blessed) Eadlufugeard (Garden) stretches out before you. Its 400 inhabitants are known to trade in art. Trade DCs - Food: 14 Materials DC: 13 Goods DC: 12

[H: prefix = "aged,newly built,historic,modern,quiet,noisy,polluted,dirty,tidy,rustic"]
[H: PrefixChoice = listGet(prefix,max(0,1d10-1))]

[H: name1 = "(Forest) Holt,(Forest) Weald,(Wood) Wudu,(Forest Grove) Wudubearu,(Wild Forest) Wuduwestern,(Hill Burial) Beorg,(Stone) Clud,(Cairn) Hlaew,(RIdge) Hlinc,(Hill) Hyll,(Hill of Meeting) Motbeorh,(Protecting Hill) Mundbeorg,(Neighboring Hill) Neahdun,(Rocky Hill) Stanbeorg,(Hill of Calamity) Hearmbeorg,(The Cursed) Awyrgda,(Cursed) Wearg,(Blessed) Eadgiefu,(Blessed) Eadlufu,(Under Heaven) Swegl,(Mighty Blessing) Domeadig"]
[H: Name1Choice = listGet(name1,max(0,1d21-1))]

[H: name2 = "cyth (Kinship),eardlufu (Dear Home),frumsceaft (Origin),geard (Garden),grornhof (Sad Home),ham (Hamlet),heofonham (Heavenly Home),lufe (Loved Home),manhus (Home of Wickedness),samodeard (Common Home),windgeard (Home of Sea Winds),ceasterwic (Village),cotlif (Hamlet),tun (Enclosure),thorp (Farm Village)"]
[H: Name2Choice = listGet(name2,max(0,1d15-1))]

[H: goods = "alcohol,animal textiles,antiques,art,exotica,gems and precious stones,honey,intermediate products,meat,metal goods,plant textiles,produce,raw materials,salt,slaves,spices,stone,wooden goods"]
[H: GoodsChoice = listGet(goods,max(0,1d18-1))]

[H: suffix = "50,200,400"]
[H: SuffixChoice = listGet(suffix,max(0,1d3-1))]

[H: food = 1d8+8]
[H: materials = 1d12+8]
[H: goods = 1d8+8]

[R: strformat("The %{PrefixChoice} village of %{Name1Choice}%{Name2Choice} stretches out before you. Its %{SuffixChoice} inhabitants are known to trade in %{GoodsChoice}. Trade DCs - Food: %{food} Materials DC: %{materials} Goods DC: %{goods}")] 

Add Selected Tokens to Initiative

To speed things up, I created a handy macro to allow the DM to add all selected tokens to the initiative roster with one click.

[h: initList = "booga=-1"];
 [h, foreach(Selected, getSelected("json")), CODE:
 	[SelectedGMName = getTokenImage()]
 	[arr = json.fromStrProp(initList)]
 	[if(json.contains(arr, SelectedGMName) != 0), CODE:
 		[init = json.get(arr, SelectedGMName)]
 		[result = 1d20] 
 		[init = result + getProperty("Initiative", Selected)] 
 		[tie = getProperty("Dexterity", Selected) / 100] 
 		[init = init + tie]
 		[initList = concat(initList, ";", SelectedGMName, "=", init)]
 [h: sortInitiative()]
 [h,foreach(Selected, getSelected("json")), CODE:
 	[init = getInitiative()]
 	[init = floor(init)]

Initiative Helper

Tired of having to remind players when it was their turn, I made a quick macro to advance the intiative, tell a player it's their turn, and let the next player know their turn is coming up. Its output looks similar to this, although the real thing has extra formatting to make it prettier:

Round Number 1: You're up, Sadon Kidd! Thomas Lafitte, prepare yourself!

<hr />
[h: jsonInit = getInitiativeList() ]
[H: ThisChar = nextInitiative() ]
[H: AllTokens = json.get(jsonInit, "tokens")]
[H: YourUP = json.get(json.get(AllTokens, ThisChar), "tokenId")]
Round Number [r: getInitiativeRound()]: <font size=4><b>You're up, {getName(YourUP)}!</b></font><BR />
[H:NextChar = if(ThisChar == initiativeSize()-1,0, ThisChar+1)]
[H: YourUP = json.get(json.get(AllTokens, NextChar), "tokenId")]
<i>{getName(YourUP)}, prepare yourself!</i>
<hr />