*-------------------
*Macros Tutorials
*-------------------
Why use Macros?
They allow commonly used actions to be automated. Contrary to what is often seen on the forums, they only need to be as complicated as you want them to be. Simple macros can update a token's hitpoints, or roll a skill check. Macros that are stored on the tokens are saved when you save the token, so you can just write them once!
What builds support Macros?
Good question...I'm always using the latest....I should figure this'n out.
What do I have to do to use macros?
It depends on the build, and the complexity of the macro. I'm under the impression most macros are best used on tokens, where they have full access to the tokens properties ("stats"), so having the appropriate token properties is usually the only requirement if you're using a relatively modern build. More recent builds have a "run macro on each token" option (right click on the macro button to see this), which allows macros to be written in the global or campaign context, but still access token properties. Both are very useful. You might use a token macro to allow a PC to automatically calculate and roll his attack roll. On the other hand, you might use a global macro to output the hitpoints of all the PCs at once, or as we'll see later, ask for a series of "attack rolls" to compare against monsters "defenses."
In this tutorial, I may resort to 4e terminology, just because that's what's on my mind. I hope things will be useful in a general context, and I hope that this thread can become a place to ask questions and receive answers about macros, system specific or not.
*-------------
* Macro Basics
*-------------
We should first distinguish between the two ways we can roll dice in the MapTool. These are [] and {}. The [] notation will output everything involved in the formula, while the {} notation gives only the final result.
So if I enter: "I attack the Darkness! {1d20}" I expect the below text to appear, supposing my name is Justin (and it is!):
Whereas, had I entered, "I attack the Darkness! [1d20]" I expect a more verbose output.justin: I attack the Darkness! 11
Since many macros use a lot of properties, the [] notation can cause an awful lot of text to appear, so many people prefer {}, and trust the result. I'll be using {} in the following text.justin: I attack the Darkness! « 1d20 = 16 »
We must now discuss variables. They come in 3 flavors: Token-Properties, Macro-Defined, and Prompted-For.
Token-Properties are defined on the token. A macro run on a token (whether the macro belongs to the token, or you've elected "run this macro on selected tokens" on a global macro) has access to all of a Token's Properties. Macro Defined variables make their first appearance on the left hand side of an =. They are good in the body of the macro, and then they disappear. There's no "saving" of variables between macros, or between macro runs, except for Token Properties. "Prompted for" variables are those that are used without ever having been on the left hand side of an =. The program will bring up a dialogue asking for the value of the variable, EVERY TIME YOU USE IT in this case. A common way around this will be seen in the "Healing" macro further down.
A short dialogue on a standard programming practice, and one that is used in MapTool macroing. "=" does not mean what it means in a mathematical sense. Instead it means "take whatever is on the right hand side of the =, and store it in the variable on the left hand side. So, if we wanted to update the variable "x" to 7, we might type: {x=7}. Or, if we pretend HP is a token property (not unlikely!) and we wanted to subtract 10 from it. We might enter {HP=HP-10}. But let's be honest, taking 10 HP off every time is probably not the most useful macro. Fortunately for you, dear reader, it's time to write our first macro!
Select your token, and make sure it has the property "HP" and it might be useful at this time to add the property "MaxHP" (your DM can add properties using the campaign properties option in the edit menu). Now, open the "selected" window, (window>selected), and right click, and elect "add new macro." We'll name the macro "Take Damage" In the body of the macro, we should type, {HP=HP-damageTaken}. Click OK. Now, if you run the macro, you'll notice that a dialogue pops up for damageTaken, where you would provide input. (If HP is prompted for, that means you didn't have anything in the property to begin with. This should only happen once).
Woohoo! You've written your first macro! Or, you watched me write a macro, and you're taking my word for it. Whatever the case, we should take some time to learn about prettying up our output. I know I know, I already said that {} only shows the last number and whatnot. Take into consideration however, what token you may have put this macro on. Was it a PC token? Then just seeing the number output might not mean too much. Was it a monster token? Then seeing the number output is the last thing you want your players to see!
Anything you don't put in {} or [] will show up, just like it would in the chat window. So if it was a player token, we might do the following:
Right click on the macro, and choose "Edit Macro." Change the Macro Command field to read: "Current HP : {HP=HP-damageTaken}".
On the other hand, for a monster's macro, we would like to hide the numeric output. So we'll learn a technique due to BigO, which is to use HTML comments to hide output. The idea is that anything contained in <!-- ... --> will not be seen, though it is still executed. So we might change the macro to: "<!-- {HP=HP-damageTaken}--> Ouch!", so that when click the macro for the monster, you can update the HP, but all the players see is the monster saying "Ouch!" Neat, huh?
At this point, you could use this macro and enter a negative number to heal your token. There's just one problem with that strategy...You might "overheal." We'll tackle this problem with a new macro, we'll call it "Heal," and a handy function built into MapTool, called "min". The min function works like this: min(x,y) spits out whichever the smaller of x, or y, is. so min(1,2) gives 1, min(10,-2) gives -2. We'll use this to compare HP to MaxHP, so that we correct any overhealing. The Heal macro might look like (for a player):
Code: Select all
Received Healing {Healed=Healed} <br>
Current HP: {HP=min(HP+Healed,MaxHP)}
You might have noticed that I explained the above macro using "if then" logic. We could in fact have used the if statement to implement it! First, a brief discussion on how if statements work.
The syntax for "if" is if(condition,then,else). The way to think about it, is that if condition evaluates to true, the if clause will become the "then" portion, while should the condition be false, the clause will become the "else" portion. The condition can use any of the following operators:
x > y, is true if x is greater than y, false otherwise.
x >= y, is true if x is greater than OR equal to y, false otherwise.
x < y, is true if x is less than y, false otherwise.
x <= y is true if x is less than OR equal to y, false otherwise.
x == y is true if x is equal to y, false otherwise.
x != y is true if x is NOT equal to y, false otherwise.
There's also some more advanced symbols we can use, && for "and" and || for "or". They work like this:
true && true = true
true && false = false
false && true = false
false && false = false
true || true = true
true || false = true
false || true = true
false || false = false
So "AND" is only true if both sides are true, and "OR" is true if either side is true. So if we wanted to check if x > y AND x < z, we could use (x>y)&&(x<z).
So if we typed {if(1>0,"Beep","Arr!")} into the chat, we would see the output "Beep", whereas if we typed {if(1==0,"Beep","Arr!")} into the chat, we would see "Arr!" One important thing to note, you can put expressions (like 1d20+7) in the "then" or "else" part, but YOU CANNOT PUT AN =. Don't do it! The = has to go BEFORE "if"! Instead, let's see how to use "if" to check if we overflowed on the heal, and assign HP properly.
Code: Select all
Amount Healed {Healed=Healed}
Current HP: {HP = if(HP+Healed > MaxHP, MaxHP, HP+Healed)}
Let's now learn how to set states in the macros. We use the syntax state.NameofState . So let's suppose we want to update our Take Damage macro to change our state to "Dead" should our HPs go to 0 or less. That is, we want state.Dead=1 if we died, state.Dead=0 if the GM will kill us later. (1 means "on", 0 means "off").
Your Take Damage macro code might look like:
Code: Select all
Current HP: {HP=HP-damageTaken}
<!-- {state.Dead=if(HP<=0,1,0)} -->
Let's also update our Healing macro, to show how you can use also use states in the if statement.
Some systems use the convention that if you receive healing when you are at negative HP, the healing starts from 0. We'll use that here. We might change our Healing Macro to something like this:
Code: Select all
Healing Received: {Healed=Healed}
HP are now: {HP = if(state.Dead==1, Healed,HP+Healed)}
<!-- state.Dead=0 -->
Storing dice rolls in variables, and storing dice rolls in properties.
Let's assume you're using a system "like 4e" (that is, I'll use some 4e things as I darn well please, and ignore things that will bloat the macro), where 1/2 your level (round down) is factored into a melee attack, and 1/2 your strength is also factored into your attack. And that you store weapon dice (say 1d6 for a shortsword, 1d8 for a longsword) in a token property "CurrentWeaponDice." Also, we'll store the weapon's critical range (roll >= than this to get a crit), in "CurrentWeaponCrit." For now we'll ignore magical weapon bonuses, feat bonuses, and the like. These are easy to add in with extra token properties, if you understand the following macro.
This is where this thread becomes very specific to build 39. In previous builds, you could store "CurrentWeaponDice" as 1d8, and then type {CurrentWeaponDice} and it would roll the die. Instead, we must treat properties exactly as we treat text. So in "CurrentWeaponDice" I will store "{1d8}".
So what we'd like to do, is roll a d20, compare that against the crit range, and output whether or not the roll was a critical threat or not, along with the damage.
So our macro might look like this. First we'll save the roll so we can use it in comparisons later. Also, the "floor" function rounds all fractions down. so floor(2.5)=2. floor(2)=2.
Code: Select all
/me makes a mathemagical attack with his {CurrentWeaponName}!
You rolled a {roll=1d20} <br>
For a total of {attackRoll=roll+floor(Level/2)+floor(Strength/2)} <br>
The damage is {Dmg=CurrentWeaponDice+floor(Strength/2)} <br>
if(roll>=CurrentWeaponCrit,"Critical Threat!","")
Notice how we split the roll away actual roll + bonuses, to more easily test for the critical.
The reason you see "CurrentWeapon" in all of these names, is because often a player attacks with more than one weapon. By making the Attack Macro make use of "CurrentWeapon" type things, we can easily introduce weapon changing macros:
Let's say I've stored my chalksword information in the Weapon1 slots. I might make a macro that looks like this, to change to my chalksword:
Code: Select all
/me sheathes his {CurrentWeaponName}, and draws out his {Weapon1Name}.
<!--
{CurrentWeaponName=Weapon1Name}
[CurrentWeaponDice="{"+Weapon1Dice+"}"]
{CurrentWeaponCrit=Weapon1Crit}
-->
Code: Select all
[CurrentWeaponDice="{"+Weapon1Dice+"}"]
One more macro that is easy to write, and I think is pretty handy for the GM. I use it for when my players use an area of effect attack, such as fireball. For simplicity, we'll assume the attack is an area attack against AC. (Armor class...it's a defensive stat. If your attack exceeds the enemy defense, you hit).
This macro goes in the GLOBAL context, even though it'll access token properties. To use this, I also create two custom states, one I call "Hit" and another I call "Miss". (edit > campaign properties > states tab). The goal of the macro is for me to prompt the player for a series of attack rolls, which I will rate against each token's defense, and set the state to Hit or Miss. This lets me tell which damage to apply to what token, (maybe with a "Take Damage" macro we already wrote? hmmmmm?!):
Code: Select all
<!--
{roll=attackRoll}
{state.Hit=if(roll>=AC,1,0)}
{state.Miss=if(roll<AC,1,0)}
-->
If I select a group of monsters, and right click on this macro and select "run for each selected", it asks me for the attack roll against each monster. Then it gives me a _visualization_ of whether the monster was hit or missed. I can then add the damage with a group macro to all the hit monsters, and to all the missed monsters seperately. I also advise a Hit/Miss clearing macro:
Code: Select all
<!--
{state.Hit=0}
{state.Miss=0}
-->
So that's it for "Basic" macros. I hope this gets you started in adding some macros to your tokens and campaigns to speed things up a bit so that you can get back to the real game!
*------------------------
* Advanced Macro Features
*------------------------
For now, I'll ask you to view my thread about if/then/else/else if for a more detailed look at what can be done with the if command. The link is here:
http://forums.rptools.net/viewtopic.php?t=4831
You can also use tables in macros now, but they will not display the image, if there is one associated. The syntax is:
{tbl("MyTable",myRoll)} where the quotes around MyTable are CRITICAL.
*--------------------------------------------------
* Macro Troubleshooting & Common Solutions
*--------------------------------------------------
-Sometimes, you have some problems with your macros. I want to address some of those here. Remember if you are converting macros from previous builds, you might need to put {} around your properties, in build 39 if a property stores a dice roll, you have to wrap it in {}.
-Sometimes you get unexpected math results. That's because of this crazy little thing called order of operations. In macros, parenthesis make a HUGE difference. For instance 2*3+1 is different from 2*(3+1). The order of operations is everything in parenthesis happens first, then power,multiply, divide, add, subtract, and then the last thing that ever happens is =. An example is appropriate here:
2*3+1
->6+1
-->7
whereas
2*(3+1)
->2*(4)
-->8
*-------------
* TO DO LIST
*-------------
-Cover Various Strings in Macros
-Using tables to "spice up" macros
-Incorporate / Update if-then-else directly into this thread
-Using if-then-else and copy/paste to imitate for loops for multiple attack rolls
-Incorporate "Tables in macros and a cute trick" thread, maybe using salmelo's Marvel thread as an example of "variable variable names"
-Make formatting prettier, less rambly.
-Reexplain if stuff
*Note to self: First macro, dice rolls. Second macro, dice rolls with user input. Third macro, add text. Fourth macro, hide dice rolls, show output. Fifth Macro: HP update macro.
*---------------
* Disclaimer
*---------------
This is a rough draft of the Macros tutorial, I want to get questions / comments so that it can be as useful as possible. Thanks!
Please don't forget to disable HTML when posting macros, or when quoting this thread![/img]