MapTool Macros

Last update: March 15, 2012

If there are any macros you’re looking for that you don’t see here, please leave a comment or send me an email – I’m always happy to try to custom-write macros in MapTool!

Note that all of my macros assume that you’re using my properties and that monsters are using the Monster properties and PCs are using the Basic properties (see the end of this page for my properties).

Basic dice macros (download MapTool macro package file)

d20 roll: <b>[d20]</b>

All basic PC macros (MapTool macro package file)

Sample PC (MapTool token)

All basic monster macros (MapTool macro package file)

Sample Monster (MapTool token)

Jump to individual macros:

Single Target Attack (from a PC):

Note: In order to change this into any other single target attack, you should only need to modify the first nine lines.

[h: AttackName="SingleTarget"]
[h: SkillMod=StrMod]
[h: Defense="AC"]
[h: NumDice=1]
[h: DamageDie=Wpn1Dmg-Wpn1Brutal]
[h: Prof=Wpn1Prof]
[h: Enh=Wpn1Enh]
[h: CritDamageDie=Wpn1Crit]
[h: DamageString="damage."]
[h: DamageRoll=roll(NumDice,DamageDie)+NumDice*Wpn1Brutal]
[h: AttackBonus=SkillMod+HalfLevel+Prof+Enh]
[h: DamageBonus=SkillMod+Enh]
[h: d20roll=d20]
[h, if(CritDamageDie > 0), CODE:
 { [CritBonus=roll(Enh,CritDamageDie)]  };
 { [CritBonus=0] }
]
[h: AttackRoll=d20roll+AttackBonus]
[h: MaxDamage=NumDice*DamageDie+DamageBonus+CritBonus]
[h: RegularDamage=DamageRoll+DamageBonus]
<b>[AttackName]</b><br>
Attack: [d20roll] + [AttackBonus] = <b>[AttackRoll]</b> versus [Defense]<br>
[if(d20roll==20), CODE:
 {<font color=Red>--CRITICAL HIT--</font><br>
 Hit: [NumDice*DamageDie] + [DamageBonus] + [CritBonus] = <b>[MaxDamage]</b> [DamageString]
 };
 {Hit: [DamageRoll] + [DamageBonus] = <b>[RegularDamage]</b> [DamageString]}
]

Multi-target attack (from a PC):

[h: AttackName="MultiTarget"]
[h: SkillMod=StrMod]
[h: Defense="AC"]
[h: NumDice=1]
[h: DamageDie=Wpn1Dmg-Wpn1Brutal]
[h: Prof=Wpn1Prof]
[h: Enh=Wpn1Enh]
[h: CritDamageDie=Wpn1Crit]
[h: DamageString="damage."]
[h: DamageRoll=roll(NumDice,DamageDie)+NumDice*Wpn1Brutal]
[h: AttackBonus=SkillMod+HalfLevel+Enh]
[h: DamageBonus=SkillMod+Enh]
[h: d20roll=d20]
[h, if(CritDamageDie > 0), CODE:
 { [CritBonus=roll(Enh,CritDamageDie)]  };
 { [CritBonus=0] }
]
[h: AttackRoll=d20roll+AttackBonus]
[h: MaxDamage=NumDice*DamageDie+DamageBonus+CritBonus]
[h: RegularDamage=DamageRoll+DamageBonus]
[h: x=input("NumberOfTargets|0|Number of targets")]
[h: abort(x)]
<b>[AttackName]</b><br>
Attacking [NumberOfTargets]  [if(NumberOfTargets==1,"creature","creatures")] in the burst.<br>
[count(NumberOfTargets,"<br>"), CODE:
 {
  [h: d20roll=d20]
  [h: AttackRoll=d20roll+AttackBonus]
  Target [r:roll.count+1]:   [d20roll] + [AttackBonus] = <b>[AttackRoll]</b> versus [Defense]
  [if(d20roll==20), CODE:
   {<font color=Red>  --CRITICAL HIT--</font> [NumDice*DamageDie] + [DamageBonus] + [CritBonus] = <b>[MaxDamage]</b> [DamageString]};{}
  ]
 }
]
<br><br>
Hit: [DamageRoll] +[DamageBonus] = <b>[RegularDamage]</b> [DamageString]

Gaining Temporary Hit Points (PC)

[h: x=input("TempsAdded|0|Number of temporary hit points gained")]
[h: abort(x)]
[if(TempHP>=TempsAdded), CODE:
 {Already has [TempHP] temporary hit points, so none were added.};
 {[h: setProperty("TempHP",TempsAdded)]
 Now has [TempsAdded] temporary hit points.}
]

Gaining Hit Points (PC version)

[h: x=input("AdditionalHP|0|How many non-surge hit points are being gained?","SurgesToSpend|0|How many surges would you like to spend?")]
[h: abort(x)]

[if(SurgesLeft<SurgesToSpend), CODE:
 {Only has [SurgesLeft] surges remaining; they will be spent.<br>
  [h: SurgesToSpend=SurgesLeft]
 };{}
]

[h: CurHP=HitPoints]
[h, if(CurHP>0), CODE:
  {[NewHP=CurHP+SurgesToSpend*SurgeValue+AdditionalHP]};
  {[NewHP=SurgesToSpend*SurgeValue+AdditionalHP]}
]

[h, if(NewHP>MaxHP), CODE:
  {[h: RegainedHP=MaxHP-MAX(HitPoints, 0)]
   [h: NewHP=MaxHP]
   [h: HitPoints=MaxHP]
  };
  {[h: RegainedHP=NewHP-MAX(HitPoints, 0)]
   [h: HitPoints=NewHP]
  }
]

[h: SurgesLeft=SurgesLeft-SurgesToSpend]

Spends [SurgesToSpend] healing [if(SurgesToSpend==1,"surge","surges")] and regains [RegainedHP] total hit [if(RegainedHP==1,"point","points")]. [HeShe] is at <b>[NewHP]</b> hit [if(NewHP==1,"point","points")]. 

[if(NewHP>BloodiedHP && CurHP<=BloodiedHP && CurHP>0), CODE:
  {[HeShe] is no longer bloodied.
    [h: setState("Bloodied",0)]};
  {}
]
[if(CurHP<=0 && NewHP<=BloodiedHP), CODE:
  {[HeShe] is no longer dying. [HeShe] is still bloodied.
    [h: setState("Unconscious",0)]};
  {}
]
[if(CurHP<=0 && NewHP>BloodiedHP), CODE:
  {[HeShe] is no longer dying. [HeShe] is no longer bloodied.
    [h: setState("Unconscious",0)]
    [h: setState("Bloodied",0)]};
  {}
]

[if(NewHP==MaxHP), CODE: {[HeShe] is at maximum health.}; {}]

Gaining Hit Points (Monster version)

[h: x=input("HealedHP|0|Numberof hit points gained")]
[h: abort(x)]

[h: CurHP=HitPoints]
[h, if(CurHP>=0), CODE:
  {[NewHP=CurHP+HealedHP]};
  {[NewHP=HealedHP]}
]

[h, if(NewHP>MaxHP), CODE:
  {[NewHP=MaxHP]
   [HealedHP=MaxHP-CurHP]};{}
]

[h: setProperty("HitPoints",NewHP)]

[g: add("Gains ", HealedHP, " hit points and is at <b>", NewHP, "</b> hit points.")]

[if(NewHP>BloodiedHP && CurHP<=BloodiedHP && CurHP>0), CODE:
  {[g: "It is no longer bloodied."]
    [h: setState("Bloodied",0)]};
  {}
]

[if(NewHP==MaxHP), CODE: {[g: "It is at maximum health."]}; {}]

[if(TempHP>0), CODE: {[g: add("<br>It also has ", TempHP, " temporary hit points.")]}; {}]

Taking Damage (PC – for a monster just make the output GM only)

[h: x=input("Dmg|0|Amount of damage taken")]
[h: abort(x)]

[h: CurHP=HitPoints]
[h: CurTemps=TempHP]
[h: Dead=-1*BloodiedHP]

[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.  [HeShe] 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.  [HeShe] now has no temporary hit points and <b>[NewHP]</b> regular hit points.
   }
  ]
 }
] 

[if(NewHP<=BloodiedHP && CurHP>BloodiedHP && NewHP>0), CODE:
  {[HeShe] becomes bloodied.
    [h: setState("Bloodied",1)]};
  {}
 ]

 [if(NewHP<=0 && NewHP>Dead && CurHP>0), CODE:
  {[HeShe] is now dying.
    [h: setState("Unconscious",1)]
    [h: setState("Bloodied",1)]
    [h: setState("Prone",1)]
  };
  {}
 ]

 [if(NewHP<Dead), CODE:
  {[HeShe] is dead.
    [h: setAllStates(0)]
    [h: setState("Dead",1)]};
  {}
 ]


Single target attack (monster version):

[h: AttackName="SingleTarget"]
[h: AttackBonus=0]
[h: Defense="AC"]
[h: NumDice=1]
[h: DamageDie=6]
[h: DamageBonus=0]
[h: Enh=0]
[h: CritDamageDie=0]
[h: DamageString="damage."]
[h: DamageRoll=roll(NumDice,DamageDie)]
[h: d20roll=d20]
[h, if(CritDamageDie > 0), CODE:
 { [CritBonus=roll(Enh,CritDamageDie)]  };
 { [CritBonus=0] }
]
[h: AttackRoll=d20roll+AttackBonus]
[h: MaxDamage=NumDice*DamageDie+DamageBonus+CritBonus]
[h: RegularDamage=DamageRoll+DamageBonus]
<b>[AttackName]</b><br>
Attack: [d20roll] + [AttackBonus] = <b>[AttackRoll]</b> versus [Defense]<br>
[if(d20roll==20), CODE:
 {<font color=Red>--CRITICAL HIT--</font><br>
 Hit: [NumDice*DamageDie] + [DamageBonus] + [CritBonus] = <b>[MaxDamage]</b> [DamageString]
 };
 {Hit: [DamageRoll] + [DamageBonus] = <b>[RegularDamage]</b> [DamageString]}
]

Multi target attack (monster version):

[h: AttackName="MultiTarget"]
[h: AttackBonus=0]
[h: Defense="AC"]
[h: NumDice=1]
[h: DamageDie=6]
[h: DamageBonus=0]
[h: Enh=0]
[h: CritDamageDie=0]
[h: DamageString="damage."]
[h: DamageRoll=roll(NumDice,DamageDie)]
[h: d20roll=d20]
[h, if(CritDamageDie > 0), CODE:
 { [CritBonus=roll(Enh,CritDamageDie)]  };
 { [CritBonus=0] }
]
[h: AttackRoll=d20roll+AttackBonus]
[h: MaxDamage=NumDice*DamageDie+DamageBonus+CritBonus]
[h: RegularDamage=DamageRoll+DamageBonus]
[h: x=input("NumberOfTargets|0|Number of targets")]
[h: abort(x)]
<b>[AttackName]</b><br>
Attacking [NumberOfTargets]  [if(NumberOfTargets==1,"creature","creatures")] in the burst.<br>
[count(NumberOfTargets,"<br>"), CODE:
 {
  [h: d20roll=d20]
  [h: AttackRoll=d20roll+AttackBonus]
  Target [r:roll.count+1]:   [d20roll] + [AttackBonus] = <b>[AttackRoll]</b> versus [Defense]
  [if(d20roll==20), CODE:
   {<font color=Red>  --CRITICAL HIT--</font> [NumDice*DamageDie] + [DamageBonus] + [CritBonus] = <b>[MaxDamage]</b> [DamageString]};{}
  ]
 }
]
<br><br>
Hit: [DamageRoll] +[DamageBonus] = <b>[RegularDamage]</b> [DamageString]

Recharge attack code (add this to an ordinary monster attack):

[h: RechargeTarget=5]
[h: RechargeRoll=d6]
[if(PowerCharged!=1), CODE:
 {[if(RechargeRoll<RechargeTarget), CODE:
   {[g: assert(1==0,add("Recharge roll = ", RechargeRoll, ". The power fails to recharge."),0)]
   };{}]
 };{[setProperty("PowerCharged",0)]}
]

Encounter Power Code (add this to an attack macro; use E2, E3, etc. for different powers)

[h, if(E1==0), CODE:
  {[assert(1==0,add("This power has already been expended."),0)]
  };{[h: E1=0]}
]
[h: setMacroProps(getMacroButtonIndex(), "color=darkgray") ]
 

Daily Power Code (add this to an attack macro; use Daily2, Daily3, etc. for different powers)

[h, if(Daily1==0), CODE:
  {[assert(1==0,add("This power has already been expended."),0)]
  };{[h: Daily1=0]}
]
[h: setMacroProps(getMacroButtonIndex(), "color=darkgray") ] 


Mutiple-Times Per Encounter Power Code (add this to an macro like Healing Word; use S2, S3, etc. for different powers)

[h, if(S1==0), CODE:
  {[assert(1==0,add("This power has already been expended."),0)]
  };{[h: S1=S1-1]}
]
[h, if(S1==0): setMacroProps(getMacroButtonIndex(), "color=darkgray") ]

Toggle visibility (Monster)

[if(getVisible()==1), CODE:
 {[h: setVisible(0)]
  [h: setState("Hidden",1)]
  [g: "This creature is now hidden."]
 };
 { [h: setVisible(1)]
  [h: setState("Hidden",0)]
  [g: "This creature is now visible."]
 }
]

Toggle States (create multiple campaign macros to use on any selected tokens, PC or monster)

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

Rolling Initiative (PC)

[h: d20Roll=d20]
[h: MyInit=d20Roll+Initiative]
Initiative = [d20Roll] + [Initiative] = <b>[MyInit]</b>
[h: addToInitiative(0,MyInit)]

Rolling Initiative (Monster)

[h: d20Roll=d20]
[h: MyInit=d20Roll+Initiative]
[g: add("Initiative = ", MyInit)]
[h: addToInitiative(0,MyInit)]

Short rest

[h: z=input("BlankVar|Do you really want to take a short rest?|Are you sure|LABEL")]
[h: abort(z)]

[h: x=input("SurgesToSpend|0|How many surges would you like to spend?")]
[h: abort(x)]

[if(SurgesLeft<SurgesToSpend), CODE:
 {Only has [SurgesLeft] surges remaining; they will be spent.<br>
  [h: SurgesToSpend=SurgesLeft]
 };{}
]

[h: CurHP=HitPoints]
[h, if(CurHP>0), CODE:
  {[NewHP=CurHP+SurgesToSpend*SurgeValue]};
  {[NewHP=SurgesToSpend*SurgeValue]}
]

[h, if(NewHP>MaxHP), CODE:
  {[h: RegainedHP=MaxHP-MAX(HitPoints, 0)]
   [h: NewHP=MaxHP]
   [h: HitPoints=MaxHP]
  };
  {[h: RegainedHP=NewHP-MAX(HitPoints, 0)]
   [h: HitPoints=NewHP]
  }
]

[h: SurgesLeft=SurgesLeft-SurgesToSpend]

Takes a short rest, spending [SurgesToSpend] healing [if(SurgesToSpend==1,"surge","surges")] and regaining [RegainedHP] hit [if(RegainedHP==1,"point","points")]. [HeShe] is at <b>[NewHP]</b> hit points. Encounter powers are recharged.

[if(NewHP>BloodiedHP && CurHP<=BloodiedHP && CurHP>0), CODE:
  {[HeShe] is no longer bloodied.
    [h: setState("Bloodied",0)]};
  {}
]
[if(CurHP<=0 && NewHP<=BloodiedHP), CODE:
  {[HeShe] is no longer dying. [HeShe] is still bloodied.
    [h: setState("Unconscious",0)]};
  {}
]
[if(CurHP<=0 && NewHP>BloodiedHP), CODE:
  {[HeShe] is no longer dying. [HeShe] is no longer bloodied.
    [h: setState("Unconscious",0)]
    [h: setState("Bloodied",0)]};
  {}
]

[if(NewHP==MaxHP), CODE: {[HeShe] is at maximum health.}; {}]

[h: TempHP=0]
[h: DeathSaves=0]
[h: setState("Unconscious",0)]
[h: setState("Prone",0)]
[h: E1=1]
[h: E2=1]
[h: E3=1]
[h: E4=1]
[h: E5=1]
[h: E6=1]
[h: E7=1]
[h: E8=1]
[h: E9=1]
[h: E10=1]
[h: E11=1]
[h: E12=1]
[h: E13=1]
[h: E14=1]
[h: E15=1]
[h: S1=2]
[h: S2=2]
[h: S3=2]
[h: SecondWind=1]

[h, foreach(currentMacroName, getMacros()), CODE:
  {
  [h, foreach(currentMacroIndex, getMacroIndexes(currentMacroName)), CODE:
   {
    [h: myProps=getMacroProps(currentMacroIndex)]
    [h: currentButtonColor=getStrProp(myProps, "color")]
    [h: currentFontColor=getStrProp(myProps, "fontColor")]
    [h: encounterPower=if(currentFontColor=="red" || currentFontColor=="purple", 1, 0)]
    [h: changeThisButton=if(currentButtonColor=="darkgray" && encounterPower==1, 1, 0)]
    [h, if(changeThisButton==1): setMacroProps(currentMacroIndex, "color=default") ]
    [h, if(currentMacroName=="Second Wind"): setMacroProps(currentMacroIndex, "color=orange") ]
  }]
}]

Extended rest

[h: x=input("BlankVar|Do you really want to take an extended rest?|Are you sure|LABEL")]
[h: abort(x)]

Takes a extended rest.  All powers are recharged. Hit points and healing surges are regained.

[h: setAllStates(0)]
[h: TempHP=0]
[h: HitPoints=MaxHP]
[h: SurgesLeft=DailySurges]
[h: ActionPoints=1]
[h: DeathFails=0]
[h: E1=1]
[h: E2=1]
[h: E3=1]
[h: E4=1]
[h: E5=1]
[h: E6=1]
[h: E7=1]
[h: E8=1]
[h: E9=1]
[h: E10=1]
[h: E11=1]
[h: E12=1]
[h: E13=1]
[h: E14=1]
[h: E15=1]
[h: S1=2]
[h: S2=2]
[h: S3=2]
[h:Daily1=1]
[h:Daily2=1]
[h:Daily3=1]
[h:Daily4=1]
[h:Daily5=1]
[h:Daily6=1]
[h:Daily7=1]
[h:Daily8=1]
[h:Daily9=1]
[h:Daily10=1]
[h:Daily11=1]
[h:Daily12=1]
[h:Daily13=1]
[h:Daily14=1]
[h:Daily15=1]
[h: SecondWind=1]

[h, foreach(currentMacroName, getMacros()), CODE:
  {
  [h, foreach(currentMacroIndex, getMacroIndexes(currentMacroName)), CODE:
   {
    [h: myProps=getMacroProps(currentMacroIndex)]
    [h: currentButtonColor=getStrProp(myProps, "color")]
    [h: currentFontColor=getStrProp(myProps, "fontColor")]
    [h: encounterOrDaily=if(currentFontColor=="red" || currentFontColor=="blue" || currentFontColor=="purple", 1, 0)]
    [h: changeThisButton=if(currentButtonColor=="darkgray" && encounterOrDaily==1, 1, 0)]
    [h, if(changeThisButton==1): setMacroProps(currentMacroIndex, "color=default") ]
    [h, if(currentMacroName=="Second Wind"): setMacroProps(currentMacroIndex, "color=orange") ]
  }]
}]

Death saving throw

[h: d20roll=d20]
Death saving throw result: <b>[d20roll]</b>. 

[h: DeathFails = if(d20roll<10, DeathFails+1, DeathFails)]

[if(DeathFails==3), CODE:
  {<br><br>[HeShe] is dead.
    [h: setAllStates(0)]
    [h: setState("Dead",1)]};
  {[HeShe] has failed [DeathFails] death saving [if(DeathFails==1, "throw", "throws")] so far.}
]

[if(d20roll==20), CODE:
  {[if(SurgesLeft>0), CODE:
    {[h: HitPoints=SurgeValue]
     [h: SurgesLeft=SurgesLeft-1]
     [h: setState("Unconscious",0)]
     <br><br>[HeShe] miraculously musters some inner willpower and regains consciousness! [HeShe] spends a healing surge and now has [HitPoints] hit points.
    };
    {<br><br>[HeShe] attempts to mustering tremendous willpower but has no healing surges and is still dying.}
   ]
  };
  {}
]

Second wind

[h: x=input("AdditionalHP|0|How many non-surge hit points are being gained?")]
[h: abort(x)]

[h, if(SecondWind==0), CODE:
  {[assert(1==0,add("You have already used your second wind this encounter."),0)]
  };{[h: SecondWind=0]}
]
[h: setMacroProps(getMacroButtonIndex(), "color=darkgray") ]

[if(SurgesLeft<=0), CODE:
 {Has no healing surges remaining.<br>
  [h: SurgesSpent=0]
 };{[h: SurgesSpent=1]}
]

[h: CurHP=HitPoints]
[h, if(CurHP>0), CODE:
  {[NewHP=CurHP+SurgesSpent*SurgeValue+AdditionalHP]};
  {[NewHP=SurgesSpent*SurgeValue+AdditionalHP]}
]

[h, if(NewHP>MaxHP), CODE:
  {[h: RegainedHP=MaxHP-MAX(HitPoints, 0)]
   [h: NewHP=MaxHP]
   [h: HitPoints=MaxHP]
  };
  {[h: RegainedHP=NewHP-MAX(HitPoints, 0)]
   [h: HitPoints=NewHP]
  }
]

[h: SurgesLeft=SurgesLeft-1]
[h: setState("+2 Defense",1)]

Takes the second wind action, regaining [RegainedHP] total hit [if(RegainedHP==1,"point","points")] and getting a +2 bonus to all defenses until the end of the next turn. [HeShe] is at <b>[NewHP]</b> hit [if(NewHP==1,"point","points")]. 

[if(NewHP>BloodiedHP && CurHP<=BloodiedHP && CurHP>0), CODE:
  {[HeShe] is no longer bloodied.
    [h: setState("Bloodied",0)]};
  {}
]
[if(CurHP<=0 && NewHP<=BloodiedHP), CODE:
  {[HeShe] is no longer dying. [HeShe] is still bloodied.
    [h: setState("Unconscious",0)]};
  {}
]
[if(CurHP<=0 && NewHP>BloodiedHP), CODE:
  {[HeShe] is no longer dying. [HeShe] is no longer bloodied.
    [h: setState("Unconscious",0)]
    [h: setState("Bloodied",0)]};
  {}
]

[if(NewHP==MaxHP), CODE: {[HeShe] is at maximum health.}; {}]

Shaman summon/dismiss spirit companion

[h: MyX=getTokenX()]
[h: MyY=getTokenY()]
[if(getVisible("Spirit")==1), CODE:
 {[h: setVisible(0, "Spirit")]
  [h: setState("Hidden",1, "Spirit")]
  Spirit has been dismissed.
 };
 {[h: moveToken(MyX, MyY, 1, "Spirit")]
  [h: setVisible(1, "Spirit")]
  [h: setState("Hidden",0, "Spirit")]
  Spirit has been summoned.
 }
]

Elevation (numbers on a token)

 

[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)]};{}]
    }
   ]

 

Create a simple macro with a macro:

[h: MacroName="New Macro 1"]
[h: DieSize=6]
[h: MyCommand=""]
[h: MyCommand=MyCommand+encode("[h: DieToRoll="+DieSize+"]\\n”)]
[h: MyCommand=MyCommand+encode("Die Result = <b>[r: roll(1, DieToRoll)]</b> – Good job!”)]
[h: MacroProps='{"autoexecute":1, "label":"' + MacroName + '", "fontColor":"green", "command":"' + decode(MyCommand) + '"}']
[h: createMacro(MacroProps)]

 


Create monster power:

[h: listActionTypes = "2. Traits, 3. Standard Actions, 4. Move Actions, 5. Minor Actions, 6. Triggered Actions"]
[h: listDamageLevel = "Minion, Very Low, Low, Normal, High, Very High, Extreme"]
[h: listUsage = "At-Will, Recharge, Encounter, Not Applicable"]
[h: x = input(
  "MacroName | NewPower| Power Name || WIDTH=20",
  "TargetRange | (M1) | Targets-Aura-Etc || WIDTH=10",
  "ActionType | " + listActionTypes + " | Action Type | LIST | VALUE=STRING SELECT=1",
  "SortOrder | 1 | Sort order || WIDTH=2",
  "Usage | " + listUsage + " | Usage | LIST | VALUE=STRING SELECT=0",
  "NumberOfTargets | Single-Target, Multi-Target, No Targets | Number of Targets | LIST | VALUE=STRING SELECT=0",
  "AttackRollRequired | 1 | Attack roll? | CHECK | ",
  "DamageRollRequired | 1 | Damage roll? | CHECK | ",
  "RequirementIncluded | 0 | Requirement line? | CHECK | ",
  "PreAttackEffectIncluded | 0 | Pre-attack effect? | CHECK | ",
  "MissEffectIncluded | 0 | Miss effect? | CHECK | ",
  "AftereffectIncluded | 0 | After-save effect? | CHECK | ",
  "PostAttackEffectIncluded | 0 | Post-attack effect? | CHECK | ",
  "SpecialEffectIncluded | 0 | Special effect? | CHECK | "
)]
[h: abort(x)]

[h: DefenseTargeted='AC']
[h: Enhancement=0]
[h: DamageLevel="Normal"]
[h: DefaultDamageLevel=3]
[h, if(getProperty("Role")=="Brute"): DefaultDamageLevel=DefaultDamageLevel+1]
[h, if(Usage=="Recharge"): DefaultDamageLevel=DefaultDamageLevel+1]
[h, if(Usage=="Encounter"): DefaultDamageLevel=DefaultDamageLevel+2]
[h, if(NumberOfTargets=="Multi-Target"): DefaultDamageLevel=DefaultDamageLevel-1]
[h, if(getProperty("SubType")=="Minion"): DefaultDamageLevel=0]

[h: RechargeTargetInputString=if(Usage=="Recharge",encode("RechargeTarget | 2, 3, 4, 5, 6 | Recharge Target | LIST | VALUE=STRING SELECT=3"),"")]
[h: DamageRollInputString=if(DamageRollRequired==1,encode("DamageLevel | " + listDamageLevel + " | Damage Level | LIST | VALUE=STRING SELECT=" + DefaultDamageLevel),"")]
[h: EnhancementInputString=if(DamageRollRequired==1,encode("Enhancement | 0 | Extra damage on crit? | CHECK | "),"")]
[h: ExtraAttackBonusInputString=if(AttackRollRequired==1,encode("ExtraAttackBonus | 0 | Extra attack bonus | | WIDTH=2"),"")]
[h: JustEffectInputString=if(AttackRollRequired==0,encode("JustEffect | . | Effect line | | WIDTH=50"),"")]
[h: DefenseInputString=if(AttackRollRequired==1,encode("DefenseTargeted | AC, Fortitude, Reflex, Will | Defense targeted | LIST | VALUE=STRING SELECT=0"),"")]
[h: HitStringInputString=if(AttackRollRequired==1&&DamageRollRequired==1,encode("HitStringWithDamage | damage | Hit line after damage roll | | WIDTH=50"),if(AttackRollRequired==1&&DamageRollRequired==0,encode("HitStringNoDamage | .  | Hit line | | WIDTH=50"),if(AttackRollRequired==0&&DamageRollRequired==1,encode("EffectStringNoAttack | damage  | Effect line after damage roll | | WIDTH=50"),"")))]
[h: RequirementInputString=if(RequirementIncluded==1,encode("Requirement | . | Requirement | | WIDTH=50"),"")]
[h: TriggerInputString=if(ActionType=="6. Triggered Actions",encode("Trigger | . | Trigger | | WIDTH=50"),"")]
[h: PreAttackEffectInputString=if(PreAttackEffectIncluded==1,encode("PreAttackEffect | . | Pre-Attack Effect | | WIDTH=50"),"")]
[h: MissEffectInputString=if(MissEffectIncluded==1,encode("MissEffect | . | Miss Effect | | WIDTH=50"),"")]
[h: AftereffectInputString=if(AftereffectIncluded==1,encode("Aftereffect | . | Aftereffect | | WIDTH=50"),"")]
[h: PostAttackEffectInputString=if(PostAttackEffectIncluded==1,encode("PostAttackEffect | . | Post-attack effect | | WIDTH=50"),"")]
[h: SpecialEffectInputString=if(SpecialEffectIncluded==1,encode("SpecialEffect | . | Special Effect | | WIDTH=50"),"")]

[h: x = input(
  decode(RechargeTargetInputString),
  decode(RequirementInputString),
  decode(TriggerInputString),
  decode(PreAttackEffectInputString),
  decode(ExtraAttackBonusInputString),
  decode(DefenseInputString),
  decode(DamageRollInputString),
  decode(EnhancementInputString),
  decode(HitStringInputString),
  decode(MissEffectInputString),
  decode(AftereffectInputString),
  decode(PostAttackEffectInputString),
  decode(SpecialEffectInputString),
  decode(JustEffectInputString)
)]
[h: abort(x)]

[h, switch(DamageLevel), code:
  case "Minion": {
    [h: NumDice=0]
    [h: DieSize="MinionDamage"]
    [h: DamageBonus="MinionDamage"]
    [h: Enh=1]
    [h: CritDamageDie="MinionDamage"]
    };
  case "Very Low": {
    [h: NumDice="NumDice50"]
    [h: DieSize="DamageDie50"]
    [h: DamageBonus="DamageBonus50"]
    [h: Enh=Enhancement]
    [h: CritDamageDie="DamageDie50"]
    };
  case "Low": {
    [h: NumDice="NumDice75"]
    [h: DieSize="DamageDie75"]
    [h: DamageBonus="DamageBonus75"]
    [h: Enh=Enhancement]
    [h: CritDamageDie="DamageDie75"]
    };
  case "Normal": {
    [h: NumDice="NumDice100"]
    [h: DieSize="DamageDie100"]
    [h: DamageBonus="DamageBonus100"]
    [h: Enh=Enhancement]
    [h: CritDamageDie="DamageDie100"]
    };
  case "High": {
    [h: NumDice="NumDice125"]
    [h: DieSize="DamageDie125"]
    [h: DamageBonus="DamageBonus125"]
    [h: Enh=Enhancement]
    [h: CritDamageDie="DamageDie125"]
    };
  case "Very High": {
    [h: NumDice="NumDice150"]
    [h: DieSize="DamageDie150"]
    [h: DamageBonus="DamageBonus150"]
    [h: Enh=Enhancement*2]
    [h: CritDamageDie="DamageDie150"]
    };
  case "Extreme": {
    [h: NumDice="NumDice175"]
    [h: DieSize="DamageDie175"]
    [h: DamageBonus="DamageBonus175"]
    [h: Enh=Enhancement*2]
    [h: CritDamageDie="DamageDie175"]
    }
]

[h: AttackBonus=if(DefenseTargeted=='AC','DefaultAttackBonusVsAC','DefaultAttackBonusVsNAD')]

[h: MyCommand=""]
[h: MyCommand=MyCommand+encode("<b>" + MacroName + "</b> " + TargetRange + "<br>\\n")]
[h, if(RequirementIncluded==1): MyCommand=MyCommand+encode("<i>Requirement:</i> "+Requirement+"<br>\\n")]
[h, if(ActionType=="6. Triggered Actions"): MyCommand=MyCommand+encode("<i>Trigger:</i> "+Trigger+"<br>\\n")]
[h, if(PreAttackEffectIncluded==1): MyCommand=MyCommand+encode("<i>Effect:</i> "+PreAttackEffect+"<br>\\n")]

[h, if(AttackRollRequired==1), CODE: {
  [h: MyCommand=MyCommand+encode("[h: AttackBonus=" + AttackBonus + " + " + ExtraAttackBonus + "]\\n")]
  [h: MyCommand=MyCommand+encode("[h: Defense='"+DefenseTargeted+"']\\n")]
  [h: MyCommand=MyCommand+encode("[h: d20roll=d20]\\n")]
  [h: MyCommand=MyCommand+encode("[h: Enh="+Enh+"]\\n")]
  [h: MyCommand=MyCommand+encode("[h: CritDamageDie="+CritDamageDie+"]\\n\\n")]
  [h: MyCommand=MyCommand+encode("[h, if(CritDamageDie > 0), CODE:\\n { [CritBonus=roll(Enh,CritDamageDie)]  }; \\n  { [CritBonus=0] }\\n ]\\n\\n")]
  [h: MyCommand=MyCommand+encode("[h: AttackRoll=d20roll+AttackBonus]\\n")]
  }
]
[h, if(DamageRollRequired==1), CODE: {
  [h: MyCommand=MyCommand+encode("[h: DamageString='"+HitStringWithDamage+"']\\n")]
  [h: MyCommand=MyCommand+encode("[h: NumDice="+NumDice+"]\\n")]
  [h: MyCommand=MyCommand+encode("[h: DamageDie="+DieSize+"]\\n")]
  [h: MyCommand=MyCommand+encode("[h: DamageBonus="+DamageBonus+"]\\n\\n")]
  [h: MyCommand=MyCommand+encode("[h: DamageRoll=roll(NumDice,DamageDie)]\\n")]
  [h: MyCommand=MyCommand+encode("[h: NumDice="+NumDice+"]\\n")]
  [h: MyCommand=MyCommand+encode("[h: MaxDamage=NumDice*DamageDie+DamageBonus+CritBonus]\\n")]
  [h: MyCommand=MyCommand+encode("[h: RegularDamage=DamageRoll+DamageBonus]\\n\\n")]
  }
]
[h, if(NumberOfTargets=="Single-Target" && AttackRollRequired==1), CODE: {
  [h: MyCommand=MyCommand+encode("<i>Attack:</i> [d20roll] + [AttackBonus] = <b>[AttackRoll]</b> versus [Defense]<br>\\n")]
  [h, if(DamageRollRequired==1), CODE: {
    [h: MyCommand=MyCommand+encode("[if(d20roll==20), CODE:\\n")]
    [h: MyCommand=MyCommand+encode("  {<font color=red>--CRITICAL HIT--</font><br>\\n")]
    [h: MyCommand=MyCommand+encode("    <i>Hit:</i> [NumDice*DamageDie] ([NumDice]d[DamageDie]) + [DamageBonus] + [CritBonus] = <b>[MaxDamage]</b>  [DamageString]<br>\\n")]
    [h: MyCommand=MyCommand+encode("  };\\n")]
    [h: MyCommand=MyCommand+encode("  {<i>Hit:</i> [DamageRoll] ([NumDice]d[DamageDie]) + [DamageBonus] = <b>[RegularDamage]</b> [DamageString]<br>}\\n")]
    [h: MyCommand=MyCommand+encode("]\\n")]
    };
    {[h: MyCommand=MyCommand+encode("<i>Hit:</i> "+HitStringNoDamage+"\\n")]
    }
  ]
  };{}
]
[h, if(NumberOfTargets=="Multi-Target" && AttackRollRequired==1), CODE: {
  [h: MyCommand=MyCommand+encode("[h: x=input('NumberOfTargets|0|Number of targets')]\\n")]
  [h: MyCommand=MyCommand+encode("[h: abort(x)]\\n\\n")]
  [h: MyCommand=MyCommand+encode("Attacking [NumberOfTargets]  [if(NumberOfTargets==1,'target','targets')].<br>\\n")]
  [h: MyCommand=MyCommand+encode("[count(NumberOfTargets,'<br>'), CODE: {\\n")]
  [h: MyCommand=MyCommand+encode("  [h: d20roll=d20]\\n")]
  [h: MyCommand=MyCommand+encode("  [h: AttackRoll=d20roll+AttackBonus]\\n")]
  [h: MyCommand=MyCommand+encode("  <i>Target [r:roll.count+1]:</i>  [d20roll] + [AttackBonus] = <b>[AttackRoll]</b> versus [Defense]\\n")]
  [h, if(DamageRollRequired==1), CODE: {
    [h: MyCommand=MyCommand+encode("  [if(d20roll==20), CODE: {<font color=Red>  --CRITICAL HIT--</font> [NumDice*DamageDie] ([NumDice]d[DamageDie]) + [DamageBonus] + [CritBonus] = <b>[MaxDamage]</b> [DamageString]};{} ]\\n")]
    [h: MyCommand=MyCommand+encode("  }\\n")]
    [h: MyCommand=MyCommand+encode("]<br><br>\\n")]
    [h: MyCommand=MyCommand+encode("<i>Hit:</i> [DamageRoll] ([NumDice]d[DamageDie]) + [DamageBonus] = <b>[RegularDamage]</b> [DamageString]<br>\\n")]
    };
    {[h: MyCommand=MyCommand+encode("<i>Hit:</i> "+HitStringNoDamage+"\\n")]
    }
  ]
  }
]

[h, if(AttackRollRequired==0&&DamageRollRequired==1): MyCommand=MyCommand+encode("<i>Hit:</i> [DamageRoll] ([NumDice]d[DamageDie]) + [DamageBonus] = <b>[RegularDamage]</b> [DamageString]<br>}\\n")]

[h, if(MissEffectIncluded==1): MyCommand=MyCommand+encode("<i>Miss:</i> "+MissEffect+"<br>\\n")]
[h, if(AftereffectIncluded==1): MyCommand=MyCommand+encode("<i>Aftereffect:</i> "+Aftereffect+"<br>\\n")]
[h, if(PostAttackEffectIncluded==1): MyCommand=MyCommand+encode("<i>Effect:</i> "+PostAttackEffect+"<br>\\n")]
[h, if(SpecialEffectIncluded==1): MyCommand=MyCommand+encode("<i>Special:</i> "+SpecialEffect+"<br>\\n")]
[h, if(AttackRollRequired==0): MyCommand=MyCommand+encode("<i>Effect:</i> "+JustEffect+"<br>\\n")]

[h: FontColor="green"]

[h, if(Usage=="Encounter"), CODE: {
  [h: EncountersArray=getProperty("EncounterPowersDeclared")]
  [h: FirstEmptyEncounter=-1]
  [h, for(i, 9, -1, -1), CODE: 
    {[h: PowerCheck=json.get(EncountersArray,i)]
    [h, if(PowerCheck==0): EncounterPowerNumber=i]
    }
  ]
  [h: FontColor="red"]
  [h: NewArray=json.set(EncountersArray, EncounterPowerNumber, 1)]
  [h: setProperty("EncounterPowersDeclared", NewArray)]
  [h: MyCommand=MyCommand+encode("[h: PowerNumber="+EncounterPowerNumber+"]\\n")]
  [h: MyCommand=MyCommand+encode("[h: PowersCharged=getProperty('EncounterPowersCharged')]\\n")]
  [h: MyCommand=MyCommand+encode("[h: IsPowerAvailable=json.get(PowersCharged,PowerNumber)]\\n\\n")]
  [h: MyCommand=MyCommand+encode("[h, if(IsPowerAvailable==0), CODE:\\n")]
  [h: MyCommand=MyCommand+encode("  {[assert(1==0,add('This power has already been expended.'),0)]};\\n")]
  [h: MyCommand=MyCommand+encode("  {[h: NewArray=json.set(PowersCharged,PowerNumber,0)]\\n")]
  [h: MyCommand=MyCommand+encode("  [h: setProperty('EncounterPowersCharged', NewArray)]}]\\n")]
  [h: MyCommand=MyCommand+encode("[h: setMacroProps(getMacroButtonIndex(), 'color=darkgray') ]")]
  }
]

[h, if(Usage=="Recharge"), CODE: {
  [h: RechargeArray=getProperty("RechargePowersDeclared")]
  [h: FirstEmptyRecharge=-1]
  [h, for(i, 9, -1, -1), CODE: 
    {[h: PowerCheck=json.get(RechargeArray,i)]
    [h, if(PowerCheck==0): RechargePowerNumber=i]
    }
  ]
  [h: FontColor="purple"]
  [h: NewArray=json.set(RechargeArray, RechargePowerNumber, 1)]
  [h: setProperty("RechargePowersDeclared", NewArray)]
  [h: MyCommand=MyCommand+encode("[h: RechargeTarget="+RechargeTarget+"]\\n")]
  [h: MyCommand=MyCommand+encode("[h: RechargeRoll=d6]\\n")]
  [h: MyCommand=MyCommand+encode("[h: PowerNumber="+RechargePowerNumber+"]\\n")]
  [h: MyCommand=MyCommand+encode("[h: PowersCharged=getProperty('RechargePowersCharged')]\\n")]
  [h: MyCommand=MyCommand+encode("[h: IsPowerAvailable=json.get(PowersCharged,PowerNumber)]\\n\\n")]
  [h: MyCommand=MyCommand+encode("[h, if(IsPowerAvailable==0 && RechargeRoll<RechargeTarget), CODE:\\n")]
  [h: MyCommand=MyCommand+encode("  {[g: assert(1==0,add('Recharge roll = ', RechargeRoll, '. The power fails to recharge.'),0)]};\\n")]
  [h: MyCommand=MyCommand+encode("  {[h: NewArray=json.set(PowersCharged,PowerNumber,0)]\\n")]
  [h: MyCommand=MyCommand+encode("  [h: setProperty('RechargePowersCharged', NewArray)]}]\\n")]
  [h: MyCommand=MyCommand+encode("[h: setMacroProps(getMacroButtonIndex(), 'color=gray') ]")]
  }
]

[h, if(Usage=="Not Applicable"): FontColor="black"]

[h: MacroProps='{"autoexecute":1, "label":"'+MacroName+" "+TargetRange+'", "group":"'+ActionType+'", "sortBy":'+SortOrder+', "fontColor":"'+FontColor+'", "command":"'+decode(MyCommand)+'"}']
[h: createMacro(MacroProps)]

 

 

My PC properties:

-----------------------StatsToSet-----------------------------
Level:1
*Race/Class:Human Fighter
HP_Per_Level:6
BonusHP:0
MaxHP:{((Level-1)*HP_Per_Level)+BonusHP+15+Constitution}
DailySurges:{9+ConMod}
ArmorBonus:0
HeavyArmor:0
ShieldBonus:0
NeckSlotBonus:0
RefBonus:0
FortBonus:0
WillBonus:0
InitBonus:0
*Speed:6
ArmorPenalty:0
HeShe:He
-------------------AbilityScores--------------------------
Strength:10
Constitution:10
Dexterity:10
Intelligence:10
Wisdom:10
Charisma:10
---------------------------------AttackStats-----------------------------
Wpn1Enh:0
Wpn1Prof:0
Wpn1Dmg:6
Wpn1Crit:0
Wpn1Brutal:0
Wpn2Enh:0
Wpn2Prof:0
Wpn2Dmg:6
Wpn2Crit:0
Wpn2Brutal:0
Wpn3Enh:0
Wpn3Prof:0
Wpn3Dmg:6
Wpn3Crit:0
Wpn3Brutal:0
Imp1Enh:0
Imp1Prof:0
Imp1Crit:0
Imp2Enh:0
Imp2Prof:0
Imp2Crit:0
---------------------------Skills-------------------------------------
Acrobatics:{HalfLevel+DexMod-ArmorPenalty+0}
Arcana:{HalfLevel+IntMod+0}
Athletics:{HalfLevel+StrMod-ArmorPenalty+0}
Bluff:{HalfLevel+ChaMod+0}
Diplomacy:{HalfLevel+ChaMod+0}
Dungeoneering:{HalfLevel+WisMod+0}
Endurance:{HalfLevel+ConMod-ArmorPenalty+0}
Heal:{HalfLevel+WisMod+0}
History:{HalfLevel+IntMod+0}
Insight:{HalfLevel+WisMod+0}
Intimidate:{HalfLevel+ChaMod+0}
Nature:{HalfLevel+WisMod+0}
Perception:{HalfLevel+WisMod+0}
Religion:{HalfLevel+IntMod+0}
Stealth:{HalfLevel+DexMod-ArmorPenalty+0}
Streetwise:{HalfLevel+ChaMod+0}
Thievery:{HalfLevel+DexMod-ArmorPenalty+0}
--------------------BasicStats----------------------------
HalfLevel:{FLOOR(Level/2)}
Tier:{ROUND((Level+4)/10)}
-----HealthStats-----
*HP:{Hitpoints}/{MaxHP} + {TempHP}
*Surges:{SurgesLeft}/{DailySurges} ({SurgeValue} HP)
HitPoints:{MaxHP}
TempHP:0
BloodiedHP:{FLOOR(MaxHP/2)}
SurgesLeft:{DailySurges}
SurgeValue:{FLOOR(MaxHP/4)}
-----Defenses-----
*AC/Fort/Ref/Will:{ArmorClass} / {Fortitude} / {Reflex} / {Will}
ArmorClass:{10+HalfLevel+ArmorBonus+ShieldBonus+(1-HeavyArmor)*MAX(DexMod,IntMod)}
Fortitude:{10+HalfLevel+FortBonus+NeckSlotBonus+MAX(StrMod,ConMod)}
Reflex:{10+HalfLevel+RefBonus+NeckSlotBonus+ShieldBonus+MAX(DexMod,IntMod)}
Will:{10+HalfLevel+WillBonus+NeckSlotBonus+MAX(WisMod,ChaMod)}
-----OtherInfo-----
*Initiative:{DexMod+HalfLevel+InitBonus}
*ActionPoints:1
*BonusPoints:0
*DeathFails:0
------------------AbilityMods-------------------------------
StrMod:{FLOOR((Strength-10)/2)}
ConMod:{FLOOR((Constitution-10)/2)}
DexMod:{FLOOR((Dexterity-10)/2)}
IntMod:{FLOOR((Intelligence-10)/2)}
WisMod:{FLOOR((Wisdom-10)/2)}
ChaMod:{FLOOR((Charisma-10)/2)}
---------------------PowerTracking-------------------------------
E1:1
E2:1
E3:1
E4:1
E5:1
E6:1
E7:1
E8:1
E9:1
E10:1
E11:1
E12:1
E13:1
E14:1
E15:1
S1:2
S2:2
S3:2
Daily1:1
Daily2:1
Daily3:1
Daily4:1
Daily5:1
Daily6:1
Daily7:1
Daily8:1
Daily9:1
Daily10:1
Daily11:1
Daily12:1
Daily13:1
Daily14:1
Daily15:1
SecondWind:1
-----------OtherStuff------------
BeastForm:0
NativeSize:Medium
Elevation:0
AttackState:0
DefenseState:0

My Monster Properties

#---StatsToSetManually-----
#Level:1
#Role:Skirmisher
#HPModifier:8
#Spd:6
#NativeSize:Medium
#ActPts:0
#SaveBonus:0
#HeShe:It
#ArmorClassRoleMod:0
#InitiativeRoleMod:0
#Leader:0
#MinionHP:0
#SubType:Standard
#SubTypeHPMod:1
#----StatsThatCanBeDefaulted---------
#MaxHP:{((HPModifier + Constitution + (Level * HPModifier)) * SubTypeHPMod) + MinionHP}
#ArmorClass:{Level+14+ArmorClassRoleMod+ACAdj}
#Fortitude:{Level+12+FortAdj}
#Reflex:{Level+12+RefAdj}
#Will:{Level+12+WillAdj}
#Init:{HalfLevel+DexMod-ArmorPenalty+InitAdj}
#Strength:{10+HalfLevel+StrAdj}
#Constitution:{10+HalfLevel+ConAdj}
#Dexterity:{10+HalfLevel+DexAdj}
#Intelligence:{10+HalfLevel+IntAdj}
#Wisdom:{10+HalfLevel+WisAdj}
#Charisma:{10+HalfLevel+ChaAdj}
#DefaultAttackBonusVsAC:{Level+5}
#DefaultAttackBonusVsNAD:{Level+3}
#SingleTargetDamageBonus:{DamageBonus100}
#SingleTargetDamageDie:{DamageDie100}
#MultiTargetDamageDie:{DamageDie75}
#MultiTargetDamageBonus:{DamageBonus75}
#NumDice100:2
#DamageDie100:{4+FLOOR(Level/2)}
#DamageBonus100:{2+CEILING(Level/2)}
#NumDice50:1
#DamageDie50:{DamageDie100}
#DamageBonus50:{CEILING(Level/2)}
#NumDice75:1
#DamageDie75:{DamageDie100}
#DamageBonus75:{DamageBonus100}
#NumDice125:3
#DamageDie125:{DamageDie100}
#DamageBonus125:{DamageBonus100}
#NumDice150:4
#DamageDie150:{DamageDie100}
#DamageBonus150:{DamageBonus100}
#NumDice175:3
#DamageDie175:{DamageDie100}
#DamageBonus175:{2*DamageBonus100}
#MinionDamage:{4+FLOOR(Level/2)}
#-----CalculatedOrStaticStats-----
#HitPoints:{MaxHP}
#TempHP:0
#BloodiedHP:{FLOOR(MaxHP/2)}
#DeathFails:0
*#HP:{Hitpoints}/{MaxHP} + {TempHP}
*#AC/Fort/Ref/Will:{ArmorClass} / {Fortitude} / {Reflex} / {Will}
*#Type:Level {Level} {Role}
*#Speed:{Spd}
*#Initiative:{Init}
*#ActionPoints:{ActPts}
*#Str/Con/Dex:{Strength} / {Constitution} / {Dexterity}
*#Int/Wis/Cha:{Intelligence} / {Wisdom} / {Charisma}
#EncounterPowersCharged:'[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]'
#EncounterPowersDeclared:'[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]'
#RechargePowersCharged:'[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]'
#RechargePowersDeclared:'[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]'
#E1:1
#E2:1
#E3:1
#E4:1
#E5:1
#E6:1
#E7:1
#R1:1
#R2:1
#R3:1
#R4:1
#R5:1
#R6:1
#R7:1
#PowerCharged:1
---------------------------Skills-------------------------------------
#ArmorPenalty:0
#Acrobatics:{HalfLevel+DexMod-ArmorPenalty+5*AcrTrained}
#Arcana:{HalfLevel+IntMod+5*ArcTrained}
#Athletics:{HalfLevel+StrMod-ArmorPenalty+5*AthTrained}
#Bluff:{HalfLevel+ChaMod+5*BlfTrained}
#Diplomacy:{HalfLevel+ChaMod+5*DipTrained}
#Dungeoneering:{HalfLevel+WisMod+5*DunTrained}
#Endurance:{HalfLevel+ConMod-ArmorPenalty+5*EndTrained}
#Heal:{HalfLevel+WisMod+5*HeaTrained}
#History:{HalfLevel+IntMod+5*HisTrained}
#Insight:{HalfLevel+WisMod+5*InsTrained}
#Intimidate:{HalfLevel+ChaMod+5*IntTrained}
#Nature:{HalfLevel+WisMod+5*NatTrained}
#Perception:{HalfLevel+WisMod+5*PerTrained}
#Religion:{HalfLevel+IntMod+5*RelTrained}
#Stealth:{HalfLevel+DexMod-ArmorPenalty+5*StlTrained}
#Streetwise:{HalfLevel+ChaMod+5*StrTrained}
#Thievery:{HalfLevel+DexMod-ArmorPenalty+5*ThvTrained}
#AcrTrained:0
#ArcTrained:0
#AthTrained:0
#BlfTrained:0
#DipTrained:0
#DunTrained:0
#EndTrained:0
#HeaTrained:0
#HisTrained:0
#InsTrained:0
#IntTrained:0
#NatTrained:0
#PerTrained:0
#RelTrained:0
#StlTrained:0
#StrTrained:0
#ThvTrained:0
------------------AbilityMods-------------------------------
#StrMod:{FLOOR((Strength-10)/2)}
#ConMod:{FLOOR((Constitution-10)/2)}
#DexMod:{FLOOR((Dexterity-10)/2)}
#IntMod:{FLOOR((Intelligence-10)/2)}
#WisMod:{FLOOR((Wisdom-10)/2)}
#ChaMod:{FLOOR((Charisma-10)/2)}
#HalfLevel:{FLOOR(Level/2)}
-----------------Adjustments-------------------
#StrAdj:0
#ConAdj:0
#DexAdj:0
#IntAdj:0
#WisAdj:0
#ChaAdj:0
#ACAdj:0
#FortAdj:0
#RefAdj:0
#WillAdj:0
#InitAdj:0
---------------Other-----------------------------------------
Elevation:0
AttackState:0
DefenseState:0
DamageState:0
OngoingState:0
VulnerableState:0
ResistState:0
[h: x=input(“AdditionalHP|0|How many non-surge hit points are being gained?”,”SurgesToSpend|0|How many surges would you like to spend?”)]
[h: abort(x)][if(SurgesLeft<SurgesToSpend), CODE:
{Only has [SurgesLeft] surges remaining; they will be spent.<br>
[h: SurgesToSpend=SurgesLeft]
};{}
][h: CurHP=HitPoints]
[h, if(CurHP>0), CODE:
{[NewHP=CurHP+SurgesToSpend*SurgeValue+AdditionalHP]};
{[NewHP=SurgesToSpend*SurgeValue+AdditionalHP]}
][h, if(NewHP>MaxHP), CODE:
{[h: RegainedHP=MaxHP-MAX(HitPoints, 0)]
[h: NewHP=MaxHP]
[h: HitPoints=MaxHP]
};
{[h: RegainedHP=NewHP-MAX(HitPoints, 0)]
[h: HitPoints=NewHP]
}
][h: SurgesLeft=SurgesLeft-SurgesToSpend]Spends [SurgesToSpend] healing [if(SurgesToSpend==1,”surge”,”surges”)] and regains [RegainedHP] total hit [if(RegainedHP==1,”point”,”points”)]. [HeShe] is at <b>[NewHP]</b> hit [if(NewHP==1,”point”,”points”)].[if(NewHP>BloodiedHP && CurHP<=BloodiedHP && CurHP>0), CODE:
{[HeShe] is no longer bloodied.
[h: setState(“Bloodied”,0)]};
{}
]
[if(CurHP<=0 && NewHP<=BloodiedHP), CODE:
{[HeShe] is no longer dying. [HeShe] is still bloodied.
[h: setState(“Unconscious”,0)]};
{}
]
[if(CurHP<=0 && NewHP>BloodiedHP), CODE:
{[HeShe] is no longer dying. [HeShe] is no longer bloodied.
[h: setState(“Unconscious”,0)]
[h: setState(“Bloodied”,0)]};
{}
][if(NewHP==MaxHP), CODE: {[HeShe] is at maximum health.}; {}]

12 thoughts on “MapTool Macros

  1. Wow. That’s a great resource. I’ve been building macros in MapTool for a while, but it’s nice to see easily modifiable examples. I will probably use them as I would like to rebuild my champaign file from the ground up again.

    Have you tried automating condition tracking? That’s what I am currently doing. I have a button for the DM which advances the initiative forward and checks to see if the character has ongoing damage and automatically subtracts the appropriate amount of damage from the PCs hitpoints and then at the end of their turn, it asks the DM if the character saved against the ongoing damage. I did have some conditions in the button as well, but I monumentally screwed that up so have gone back to just ongoing damage. I will finish it…some day 🙂

    • So far I’ve only automated the tracking of the Bloodied condition (as part of the damage and HP gaining macros), but I had a discussion with some of my players at TactiCon this past weekend about broader condition tracking. At the time I thought no, that would be too much work, but hearing you talk about it, I think it could be done.

      I’m thinking it would be a two-part macro. Part one would be in the “apply condition” button. It would give the DM the option of specifying an expiration of the condition (no expiration, beginning of a turn, end of a turn). If you choose a beginning or end of turn, you would then need to specify which creature’s turn you’re talking about (and in the case of “end of your next turn” conditions, whether it’s the current turn or the next one).

      Part two would be in the initiative advancing macro, which I don’t currently have (I just use the button in the initiative window itself). At each advance, it would check to see whose turn just ended and whose turn just began and whether there are any conditions that end at those times (and if so, remove them).

      Hmm, possibly doable! I’m feeling a little more inspired now.

  2. Oh yes. I forgot to mention that it is split into two stages. I have my place ongoing damage button and then the advance initiative button. I tried a third button for placing conditions, but as I said, I have made a mess of the conditions so I have removed that so I can start again.

    If you want I can send you the code when I get home? It won’t be very pretty and uses my campaign properties (which includes specific properties for the types of ongoing damage).

    Annoyingly my wife plays a Warden (we have 4 remote players as well, which is why we use MapTool), so I needed to take into account the fact she can save at the start of her turn. Which does make it a bit more complicated.

  3. The healing monsters macro doesn’t work as of 1.3.86b, or is not easily integrated. It asks me for the value to be healed, and for a value for Hitpoints, and eventually just sets the health at whatever number I place in for Hitpoints, regardless of what I put in for healing, which defeats the purpose of making a macro.

    • Hmm. I just tried it in 1.3.b86, and it worked fine.

      The macro does require that the monster have certain properties: HitPoints for the current hit point value, MaxHP for the maximum hit points, and BloodiedHP for the monster’s bloodied value. Are you using those properties?

      • I didn’t have a use for the bloodied value, using 3.5e, so I removed that portion of it, though I made sure only to use non-essential ones. I have equivalent variables “CurrentHP”, “MaximumHP”, and “TemporaryHP” for the minor mention of it, and made the necessary edits to reflect the difference in property names. That said, I did not edit “Hitpoints” into “CurrentHP”, instead believing “CurHP” was the equivalent of it, given the similar names. I’ve edited it to reflect this new information, and the macro works as intended. Thanks.

  4. Hey I made a simple Wild Shape macro for any druids you could add here if you wanted. It uses your PC properties, specifically BeastForm. I assumed 1 means in beast form and 0 means not in beast form.

    Step 1:
    -Make a table. Call it “WildShape”.
    -Edit the table.
    -Row 1: Range =0, Value=BeastImage, Picture=
    -Row 2: Range =1, Value=HumanImage, Picture=

    Step 2:
    -Make macro called “Wild Shape”
    -copy and paste the following code:
    Change Shape
    [h,switch(BeastForm),code:
    case 0: {
    [Beastform = 1]
    [h: setTokenImage(tblImage(“WildShape”, 1))]
    };
    case 1:{
    [Beastform = 0]
    [h: setTokenImage(tblImage(“WildShape”, 0))]
    };
    ]

    • Nice! With all of the MapTool stuff I’ve done so far, I still have yet to mess with tables. Thanks for providing an example!

  5. It’s probably a bit too late to ask this, but… I’m trying to edit this so the text displayed isn’t all <> and such, so that it’s easier to read. But if I change any of the values in the temporary hitpoints section of taking damage to {value} instead of [value], it doesn’t work at all!

       Error in roll for IF option.       Statement options (if any): if(CurTemps==0),CODE       Statement Body (first 200 characters): { [h: NewHP=CurHP-Dmg] Takes [Dmg] damage and is at [NewHP] hit points. [h: setProperty(“HitPoints”,NewHP)] }; { [if(Dmg=CurTemps), CODE: { [h: setProperty(“TempHP”,CurTe

    is the error I get, with [NewHP] in bold. I’m still very new to macro editing, so is there anything I’m obviously missing?

    • For the record, what I changed was

      [if(Dmg<=CurTemps), CODE:
      {
      [h: setProperty("TempHP",CurTemps-Dmg)]
      [h: NewHP=CurHP]
      Takes [Dmg] damage, losing [Dmg] temporary hit points. [HeShe] how has [CurTemps-Dmg] temporary hit points and [CurHP] regular hit points.

      to

      [if(Dmg<=CurTemps), CODE:
      {
      [h: setProperty("TempHP",CurTemps-Dmg)]
      [h: NewHP=CurHP]
      Takes {Dmg} damage, losing [Dmg] temporary hit points. [HeShe] how has [CurTemps-Dmg] temporary hit points and [CurHP] regular hit points.

      • I’m happy to help. Don’t use {} around variables like that. If you have your options set so that you’re ending up with weird stuff in the text box, switch from things like [Dmg] to [r: Dmg]. That should do the trick.

        [if(Dmg<=CurTemps), CODE: { [h: setProperty("TempHP",CurTemps-Dmg)] [h: NewHP=CurHP] Takes [r: Dmg] damage, losing [r: Dmg] temporary hit points. [r: HeShe] how has [r: CurTemps-Dmg] temporary hit points and [r: CurHP] regular hit points. -Michael the OnlineDM

Leave a Reply