A (long) MapTool macro tutorial

Doc requests, organization, and submissions

Moderators: dorpond, trevor, Azhrei

knizia.fan
Giant
Posts: 197
Joined: Wed Jul 30, 2008 3:43 pm

A (long) MapTool macro tutorial

Post by knizia.fan »

Introduction to macro programming in MapTool
(as of build 40)

(Note: as I was typing this in reply to someone's request for a macro tutorial, Dedric posted his own tutorial. Be sure to check it out! It's shorter, so you may prefer to start there.)

Folks, please correct me where I'm wrong, and provide any useful information that I'm missing.

A macro is a package of text that gets sent to the chat window as if you had typed it yourself. It's a way to automate repetitive tasks. The power of macros comes from their ability to include calculations and to modify token properties. Many macro features have been added in the last two months. I'll try to cover everything in this post.

Creating macros
Macros can be stored in three locations. The Window menu lets you view windows with buttons for all your macros (Global, Campaign, Selection, Impersonate).
  • Global: These are available to you whenever you run MapTool, in any campaign, whether you are a player or GM. They are not available to other people who are connected to your game.
  • Campaign: These are saved with the campaign file, and are used by the GM. They are not available to other people who are connected to your game.
  • Token: These are stored in a token. If you save the token to an .rptok file, the macros will be in there. Other people in your game can see your macros, if they have permission to access your token in the game.
Global and campaign macros can have a button color and hotkey, and you can decide whether the macro runs immediately or whether the button just sends its text to the chat input box. Token macros always run immediately and can't have button colors or hotkeys (yet). Token macros also auto-impersonate, so that the chat output will show the token image next to the output.

Players will want to use either global or token macros. I prefer to keep macros in tokens, since I don't want macros for different characters to be jumbled together. I'll mostly focus on writing token macros here. There are two ways to create token macros. In the token's Edit Token dialog (double-click the token to get there), there is a Macros tab. You can enter in a title and macro code on each line of the list. This is useful when you want to make several short macros.

Example: type Roll Initiative in the ID column, and the text My initiative is [1d20]. in the Action column.

To run your macro, you can right-click the token and select the macro from the Macros submenu. An easier way is to show the Selection window. When you select your token, all its macros will appear as buttons in this window. There is also an Impersonate window which shows the macros for the token you are currently impersonating, regardless of what is selected.

For longer macros, you can right-click in the Selection or Impersonate window and choose Add New Macro. This gives you a larger edit box to work with. You can edit existing macros by right-clicking their buttons. I suggest that if you begin writing multiple long macros, you should keep them in a separate text file. You can then copy the text and paste it into the edit box (type Ctrl+A to select the existing contents, and Ctrl+V to replace them with your new text).

Bug note: Currently (build 40) there is a bug where sometimes your changes are lost when you use the Edit Macro menu option. To work around this, you'll need to paste your new macro text in the token Edit Token dialog box on the Macros tab. Also, opening the token's Edit Token dialog box seems to make the changes stick (?!). The bug is in the Impersonate window. The Selection window seems to work alright.

You can easily copy macros from one token to another by selecting both tokens and dragging the macro button in the Selection window from one token to another. If you drag a macro to the "Common" area, it will be copied to every selected token.

What macros can do
There are a few cool things you can put into a macro.
  • HTML code: You can include simple HTML tags in the text of your macro to format the output. Currently only basic things are supported. Simple tables work, and "span" tags can be used with simple "style" properties for formatting. More advanced things like CSS are not available. A very useful trick when you begin to write long macros is to use HTML comments to suppress the output from part of your code. (Enclose the code in <!-- --> tags.)
  • Rolls and calculations: Any roll you could put in the chat window can be used in a macro as well. Put the roll in square brackets to show the roll to everyone for verification. Put it in curly braces to only show the final result.
  • Token properties: You can read and write values of token properties, and make decisions based on them.
Simple HTML example:

Code: Select all

<b>Initiative roll:</b> 
<br>My initiative is <span style="color:red">[1d20+3]</span>.
Image

Use the <br> tag to create a line break in your output. Since long macros need to be on multiple lines to be readable, MapTool doesn't output a separate line of text for each line of your macro. You'll need to explicitly indicate line breaks with <br>.

Fancy HTML example:

Code: Select all

<table border="0"> 
  <tr bgcolor="#CC0000"> 
    <table width="100%">
      <tr>
        <td style="padding:0px 5px;"> 
          <span style="color:white"><b>Conan strikes!</b></font> 
        </td> 
        <td style="padding:0px 5px;" align=right>
          <span style="color:white">Conan has a +5 to attack.</font>
        </td>
      </tr>
    </table>
  </tr> 
  <tr>
    <td>
      Conan swings his sword ([1d20+5]) and does ([1d8+4]) damage!
    </td>
  </tr>
</table>
Image

Now, that attack macro contains some numbers which you will have to modify every time your character's statistics change. If you have 10 or 20 macros, that will become tedious and error-prone. To make your macros easier to maintain, your code should make use of token properties. These properties are defined by the GM in the Campaign Properties dialog box. Let's say that you're using the default properties MapTool gives you, one of which is called HP. If Conan starts with 100 hit points and takes damage several times, you might want a macro to adjust his HP value without having to edit the token properties each time.

Code: Select all

Conan begins with {HP} hit points, and takes {DamageValue = DamageTaken} points of damage!
<br>Now Conan only has {HP = HP - DamageValue} hit points.
Image
  • The {HP} just prints out the current value of the property.
  • The token doesn't have DamageValue or DamageTaken properties, so these are treated as local variables which will be discarded when the macro completes. In order to assign a value to DamageValue, we need a value for DamageTaken. Since this is not a property, you will get a pop-up prompt asking for a value for DamageTaken. After you type in a value, it is assigned to DamageValue and the macro continues.
  • Finally, the {HP = HP - DamageValue} calculates the new HP value and stores it in the HP property.
Notes: You might be tempted to write your macro this way:

Code: Select all

Conan begins with {HP} hit points, and takes {DamageValue} points of damage!
<br>Now Conan only has {HP = HP - DamageValue} hit points.
However, if you do this, you will be prompted twice for the variable called DamageValue. You must use an assignment (with the = sign) to save the value you type for later use.

Also, don't try to skimp on variable names by using something like {DamageValue = DamageValue}, hoping it will prompt you once and then use that number in later uses of DamageValue. This works sometimes, but can cause subtle bugs.

If you have properties called AtkBonus and DmgBonus, you could use them in the previous fancy attack macro. When these values change, you just have to edit the properties once and all your macros will use the new values.

At this point, you know how to create macros which can nicely format your output, and you can read and write properties from your token. You can do a lot of useful things with just this. If you want to do even more complex tasks, read on.

Token Properties and other token "properties"
Token properties are defined by the GM, and show up on your token when you bring up the Edit Token dialog box by double-clicking. The Properties tab contains a list of properties. If you have entered a value for a property, then you can refer to it in a macro using [PropertyName] or {PropertyName}. If you haven't entered anything, and the campaign doesn't define a default value for that property, then you'll get a prompt if a macro tries to use that property.

Tokens also have other "properties", although the official term "Property" only refers to the entries in the Properties tab. Here are other values you can read or change on your token.
  • token.name is the token's name.
  • token.label is the token's label.
  • token.gm_name is the token's GM name (only usable by the GM).
  • token.halo is the token's halo color. It can be set using a color name "Orange" or a hex value "#FF0000".
  • token.visible shows or hides the token (only usable by the GM).
  • the token image can be read using the function getTokenImage(). You can provide a number as an argument to set the size. This can be used in an HTML <img> tag to display the image in chat.
Advanced note: Suppose you enter a value for a token property called "Damage" and then bring the token to another campaign which doesn't define that property (or your campaign decides to get rid of the property). You won't see the Damage property listed in the Edit Token dialog box anymore. But the property is still lurking there, invisible! This can confuse the heck out of you if you later use that name as a variable in a macro. Weird things will happen and you will be unhappy. Currently the only way to find such lurking properties is to crack open the token file and read through the XML. I have no other solution for you at this time. I hope that knowing of this danger will help you understand what's going on if you ever fall into this trap.

Calculations in token properties
Instead of a simple number or piece of fixed text, you may want to put formulas in your token properties. For example, D&D calculates an ability bonus from the ability score. If you have token properties Strength and StrBonus, you can put the following text inside the StrBonus property: {floor(Strength/2 - 5)}.

Note the braces around the formula! This tells MapTool that this text is a calculation, not just some text you happened to want stored in the property. (For example, if you have a "Weapon name" property with the value Longsword +1, you don't want MapTool to try to add 1 to the value of Longsword! In such a case, you don't use the braces {} and the raw text is returned.) If you've used spreadsheets before, this is similar to the way they require you to put an = sign in front of your formulas.

You might want to store your weapon die roll in a property, too. The property could be set to {1d8+1}, and every time you refer to it in a macro, the die will be rolled. (However, if you use this method, there's no way to have the die roll shown in chat for verification. All you get is the final value)

Note: The requirement to put {} around calculated token properties was a new thing in build 39, and it may be changed in a future build.

Slash commands vs evaluations
Apart from outputting the text you type, there are two ways to get MapTool to do something special. Some tasks require one or the other, and some can use either. There are "slash commands" (which are also confusingly called macros), and "inline evaluations" (which use the familiar [] and {} notation).

If you type /help in the chat window, you'll get a long list of special commands you can enter. For example, typing /cc #0000FF will change the color of your chat text to blue. You can put some of these commands inside a macro as well. Here are a few that are suitable for use in a macro.
  • /cc Sets your chat color.
  • /me Sends an emote (e.g. /me cries like a baby sends the text * Conan cries like a baby)
  • /self Sends some chat text just to yourself. This is useful if you want your macro to do something but not pollute the chat window with its output. Only you will see the output.
Technical note: When you execute a token macro, the macro code is prepended with /im TokenName:. This causes you to temporarily impersonate the token before spitting out the macro output. The result is that the output has the token image and name by its side. However, this means that some slash commands cannot be used inside a token macro, because the whole thing is jammed into one line after the /im command. For example, the following macros fail as token macros. They should work as global/campaign macros, since no impersonation is performed.

Code: Select all

/cc #ff0000
This is some red text

Code: Select all

/self This is a private note.
This text should be sent to everyone.
In general, avoid using slash commands in a token macro if possible, unless the slash command is the only line in your macro. However some slash commands can be replaced with [] evaluations, especially the /roll and /settokenproperty commands.

Available functions
Inside [] or {}, you can use rolls (1d20, 2d8e, etc.) and arithmetic (+ - * /). There are also several functions available, which you use by giving some arguments in parentheses. For example, [round(15/2)] will round the value to the nearest integer. All functions must be enclosed in [] or {} to work. Go here for a mostly complete list.
  • round(num), floor(num) Will round or lower a fraction to the nearest integer.
  • min(numbers), max(numbers) Finds the minimum or maximum of a series of numbers.
  • if(condition, truevalue, falsevalue) This is a very handy function. It returns one of two values, depending on whether the first argument is true or false.
  • tbl(table) Accesses a value from a table. Tables are a MapTool feature not described here. You can also use tbl(table, value) to access a specified result from a table.
  • Basic math functions such as add, subtract, multiply, divide, power
  • Other math functions such as abs, sum, bitwise operations (band, bnot, bor, bxor), ceil/floor/round, hex (convert to hexadecimal), hypotenuse, ln/log, min/max/mean/median, sqr (squares a number), sqrt (square root)
  • Other functions such as concat (to join strings), set (to set a variable), tblImage (gets an image from a table), getStateImage (gets the image for a state)
  • eval(string) Will treat the string as a calculation and evaluate it. This is an advanced feature.
Strings
Any text inside [] or {} is interpreted as a property or variable name when MapTool performs the calculation. Sometimes you want to embed raw text in a calculation; often this is some HTML code. If you put text inside a pair of double quotes " or single quotes ', MapTool will treat the text as a single blob and not try to interpret it. This is a somewhat advanced issue, because usually your plain text will appear outside the [] or {} symbols. If you need to embed a string within a string, you can mix the quote types.

Here's a simple, if awkward, example. Depending on the value of the variable X, you want to either print out the token's hit points or its maximum hit points. We must enclose "HP" in quotes to get it to print out, since otherwise MapTool will try to look up a property called "HP".

Code: Select all

[if( X==1, "HP = " + HP, "MaxHP = " + MaxHP )]
The if() function
To get full use from the if() function, there are a few things for you to know. The condition can be any calculation that returns a number. If the number is zero, the condition is false; otherwise it's true. More often you will use a comparison operator. These are equality ==, inequality !=, greater >, greater or equal >=, less <, less or equal <=. For example, {if(3>0, "Positive", "Not positive")} will print Positive to the output. (Note the quotes, which prevent MapTool from trying to look up a property called Positive.

You can combine conditions with logical operators: and &&, or ||, not !. For example, {if( 3>0 && -1>0, "Both positive", "Not both positive" )} will print Not both positive since one of the tests wasn't true.

Sometimes you will want the if statement to return a number. Say you want to add 3 to attack rolls if your HP are below 20. [1d20 + if(HP<20, 3, 0)] will do the trick.

Other times you want to return a string as part of your output. Sometimes you will want to build this string from several pieces, in which case you can use the string joining operator +. Note that the if() function must always have 3 arguments. Even if you want nothing to appear if the condition is false, you must include an empty string "" as the third argument.

Halos and States
You can set your token halo (a colored line around the token) to orange by using [token.halo = "Orange"]. You can read the value as well, which you might do in order to set another color (e.g. an HTML text color) to match.

Token states are graphic overlays that indicate temporary conditions. They can be set by right-clicking on a token. In a macro, you can set a state by using, e.g., [state.Dead = 1]. Note that the state names are case-sensitive. If you type state.dead, your macro won't work. You can also read the value of a state. For example, you might apply an attack penalty to prone characters. You could use [1d20 + if(state.Prone, -2, 0)]. Note that state.Prone equals 1 if the state is on, which the if function interprets as a true condition. When the state is off, state.Prone equals 0, and the if() function evaluates to 0.

You can use /sts TokenName StateName Value to set a state on a particular token. If you omit the TokenName, the /sts command modifies the currently selected tokens. If you omit the Value, the state is toggled between on and off.

States can also be read and set using functions, e.g. [getState(StateName)] or [setState(StateName, Value)]. This is useful in more advanced cases where you want to choose among several states when the macro is run. You can turn off all states using [setAllStates(0)].

The eval() function
This is an advanced feature. Sometimes you don't know the calculation you want to perform until the macro is run, so you can't code it up ahead of time. The eval() function takes a string and treats it as a calculation to be performed. This lets you build up the string from various parts when the macro is run.

For example, to roll 3 8-sided dice, we know to type [3d8]. But what if the number of dice to be rolled is different each time you run the macro? Let's say you want to prompt the user for the number. The following macro does the trick.

Code: Select all

[NumDice = How_Many_Dice]
[eval( NumDice + "d8" )]
This will prompt the user for the value of How_Many_Dice. Suppose the user types 4. The section NumDice + "d8" constructs the string "4d8", and the eval() function interprets that as a roll, which is then performed.

You could even determine the type of die at runtime too: NumDice + "d" + DieType.

With sufficiently complicated eval trickery, you can get MapTool to do many things which are not provided as built-in features. But it's difficult, and if you make a mistake the error messages you get are not at all informative. Best to save this kind of work for when you gain experience, and be sure to ask for help on the forums!

Writing macros
Let's build up a macro from simple to complex. I'll use the example of damage and healing. Let's assume that your campaign settings define the following token properties: HP, MaxHP, TempHP. It's important that your token has some number stored in each property--if you leave any of them blank, you may get surprising behavior.

Try these yourself! Start MapTool and add the MaxHP and TempHP properties to the campaign (Go to Edit > Campaign Properties. Click "Basic" in the list on the left. Click in the large list and enter 2 new lines saying *MaxHP and *TempHP. Then click the Update button, and the OK button.) Then put a token on the map and put some numbers in those properties.

A simple damage macro is below. Note the HTML comment to prevent the initial setup statement from having any output. Also note the <br> tag to force a new line, and the use of curly {} to make the output look clean.

Let's call this macro "TakeDamage". Remember, to put this macro in a token, copy the text from here, double-click the token, go to the Macros tab, enter the name in the "ID" column, click in the "Action" column, type Ctrl+A (to select all existing text there) and Ctrl+V (to replace the existing text with the new text), and click OK. Then you can run the macro from the Selection window.

Code: Select all

<!-- Ask the user for input.
       [DmgValue = DamageTaken] 
-->
{DmgValue} points of damage are taken.
<br>Hit points drop from {HP} to {HP = HP - DmgValue}.
Suppose that our game system doesn't allow HP to drop below -10. We can use a max() function to check if the hit points become too low:

Code: Select all

<!-- Ask the user for input.
       [DmgValue = DamageTaken] 
     Calculate the new value.
       [NewHP = max(-10, HP - DmgValue)] 
-->
{DmgValue} points of damage are taken.
<br>Hit points drop from {HP} to {HP = NewHP}.
Note that hit points don't drop below -10: Image

We might use negative numbers for damage to indicate healing, in which case we don't want MaxHP to be exceeded. Now we wrap the max() function in a min() function to check both boundaries. We also determine the proper verb to use in the text:

Code: Select all

<!-- Ask the user for input.
       [DmgValue = DamageTaken]
     Calculate the new value and the correct word to use.
       [NewHP = min(MaxHP, max(-10, HP - DmgValue))] 
       [Word = if(DmgValue >= 0, "drop", "rise")]     
-->
{DmgValue} points of damage are taken.
<br>Hit points {Word} from {HP} to {HP = NewHP}.
And now hit points don't rise above MaxHP (30), and the verb "rise" is used when healing is applied:
Image

If we're below 0 hit points, we'd like to set the Disabled state on the token. If we're at -10 hit points, we'd like to set the Dead state. And if we get healing, we'd like to just turn those states off. The if() function helps us here. I'm going to use the == operator to test for equality, and the && operator to test two conditions at once (logical and).

Note that I'm setting up some status variables (IsDisabled, IsDead). I can then use those variables later on, and my code is fairly readable because the names are self-explanatory. If I had just embedded the calculation in each place I needed it, the code would be much harder to read. I highly recommend this style, even though it makes your macros a few lines longer.

Also note the trick of putting a <br> inside a string. This means that a new line is only shown when that string is displayed.

An important note: you can use either double or single quotes to indicate a string. Note that I had to use both types in the <span> tag below, because I wanted a quoted string 'color:red' to be inside the larger string. If I had used the same kind of quote in both places, MapTool would become quite confused and give me the unhelpful error message "Could not execute the command: null".

Code: Select all

<!-- Ask the user for input.
       [DmgValue = DamageTaken] 
     Compute the correct word to use.
       [Word = if(DmgValue >= 0, "drop", "rise")]     
     Take the damage (or heal if damage is negative).
       [OldHP = HP]
       [NewHP = min(MaxHP, max(-10, HP - DmgValue))] 
       [HP = NewHP]
     Compute the token state.
       [IsDisabled = if(NewHP > -10 && NewHP < 0, 1, 0)]
       [IsDead     = if(NewHP == -10,             1, 0)]
       [state.Disabled = IsDisabled]
       [state.Dead = IsDead]     
-->
{DmgValue} points of damage are taken.
<br>Hit points {Word} from {OldHP} to {NewHP}.
{if(IsDisabled, "<br>I'm disabled!", "")}
{if(IsDead, "<br><span style='color:red'>I'm dead!!</span>", "")}
Now status messages appear if hit points are below 0, and the token state image appears: Image

Let's get even fancier and add a temporary hit point feature. Following D&D, we'll say that only the higher of your current and new temporary hit points count. We'll print a message if the new value is not an improvement. Let's call this macro "GainTempHP".

Code: Select all

<!-- [NewTempHP = How_Many_Temp_HP]
     [OldTempHP = TempHP]
     [TempHP = max(TempHP, NewTempHP)] 
-->
{NewTempHP} temporary hit points were gained.
{if( NewTempHP < OldTempHP, "<br>However, I already had " + OldTempHP + " temporary hit points, so no change was made.", "" )}
Now that we have temporary hit points, we must add tests to the damage macro so that temporary hit points are subtracted first. If any temporary hit points were lost, we print a message about that.

Code: Select all

<!-- Ask the user for input.
       [DmgValue = DamageTaken] 
     Compute the correct word to use.
       [Word = if(DmgValue >= 0, "drop", "rise")]     
     See how much damage goes to temporary vs. real hit points (if damage is positive).
       [DmgToTempHP = if(DmgValue > 0, min(DmgValue, TempHP), 0)]
       [DmgToRealHP = DmgValue - DmgToTempHP]
     Take damage off TempHP.
       [TempHP = TempHP - DmgToTempHP]
     Take the remaining damage off of normal hit points (which heals if damage is negative).
       [OldHP = HP]
       [NewHP = min(MaxHP, max(-10, HP - DmgToRealHP))]
       [HP = NewHP]
     Compute the token state.
       [IsDisabled = if(NewHP > -10 && NewHP < 0, 1, 0)]
       [IsDead     = if(NewHP == -10,             1, 0)]
       [state.Disabled = IsDisabled]
       [state.Dead     = IsDead]     
-->
{DmgValue} points of damage are taken.
{if( DmgToTempHP > 0, "<br>" + DmgToTempHP + " points come off temporary hit points.", "" )}
<br>Hit points {Word} from {OldHP} to {NewHP}.  Temporary hit points are {TempHP}.
{if(IsDisabled, "<br>I'm disabled!", "")}
{if(IsDead, "<br><span style='color:red'>I'm dead!!</span>", "")}
Imagine how hard that macro would be to read if I stuffed all those calculations in just the last 5 lines! Doing things step-by-step and using meaningful variable names makes the macro much easier to deal with.

In this screenshot, you can see that temp HP are only applied if better than the previous value, that healing is only applied to the real HP even if you have temporary HP, and finally that damage is first taken off the temporary HP and then the real HP.
Image

One more example, for fun. Randomized war cries! This uses the eval function to construct a variable name on the fly. Since this macro doesn't use any token properties, you can just paste it into the chat window to try it out.

Code: Select all

<!-- [Cry1 = "For Crom!"]
     [Cry2 = "Taste my steel!"]
     [Cry3 = "The vultures will feast upon your flesh!"]
     [Cry4 = "Mommy, I'm scared!"]
     [Num = 1d4]
     [VariableName = "Cry" + Num]
     [WarCry = eval(VariableName)] 
-->
Conan glares at his foe and shouts, "{WarCry}"
General tips
If your macros are short, you can write them just about any way you like and you shouldn't have major problems. Here are some suggestions to help you write longer macros without tearing your hair out.
  • Use token properties as much as possible. This will let you reuse your macros on other tokens without having to change them much (or at all).
  • Define lots of variables with meaningful names. Break up your calculations into bite-sized pieces and assign each intermediate result to a variable. This will make it far, far easier to read and fix your code than if you have a single enormous line stuffed with (+-*)/() gobbledygook. Remember that you can put all of your setup calculations inside an HTML comment and they won't pollute your output.
  • Include comments in English that explain what you are doing.
  • Write your macros in a text editor (e.g. NotePad, NotePad++, or EditPad Lite on Windows), and then copy/paste them into MapTool. It's easier to read your code in a big editor window, and you won't get confused about which token has the most recent version of your macro.
  • A very common source of error is nested [] and {}. You cannot currently put either type of bracket/brace inside another.
  • There are two ways to use a token property or variable in a calculation. Which one you use depends on whether you are inside another calculation (i.e. inside [] or {}).
    • If you are not inside [] or {}, just put the variable name inside {}. That's how almost all the macros given here work.
    • If you are inside another calculation, you must use the variable name without {}. Note in the temporary hit point macro that I had to use string joining to stuff a variable in the middle of a string, because that string was part of a larger calculation.
  • When you run into problems, MapTools does not give very useful error messages. Usually it will just say "Could not execute command: null". An easy way to find the problem is to cut your macro down to the first few lines. If it runs without error, add more and more lines of your code until you find the error. Then you'll know which line has the problem. If you broke up your macro into bite-sized lines as I recommended, you'll be able to zero in on the offending line right away.
One last note. The rptools.net forum software will mangle your posts if they contain < or > symbols. To avoid this, you must check the "Disable HTML in this post" option whenever you type or quote text with those symbols (such as this post). If you forget to do this, it will be hard for people to help you since they can't read what you wrote!

I hope you've found this useful. Please let me know if parts are not clear, or if something isn't covered that you'd like to see.

Thanks,
--k.fan

Update 8/20: clarified that the Edit Macro bug is associated with the Impersonate window.
Update 8/21: added more screenshots for different versions of the sample macro.
Last edited by knizia.fan on Thu Aug 21, 2008 3:24 am, edited 3 times in total.

bobthedog
Cave Troll
Posts: 85
Joined: Sun Aug 03, 2008 7:17 pm

Post by bobthedog »

Lots of great info here.

About the "macros not updating if you use the Edit Macro menu" bug, I have had this bug sitting around ever since the menu was introduced. And indeed, if you open and close the Edit Token window each time you change your macros, it'll make the changes work. I'll expand:

- if you edit one macro, close it, and open it again, you'll lose the changes you had made (I don't remember now if cancelling out the second time will keep the changes made the first time);
- if you edit several macros, they will all keep their changes after you open the Token window and close it;
- if you edit macros and don't make the changes permanent, running the macro will give you your old macro, not the new one. So if you were trying to fix an error and it appears to not have been fixed, make sure you "saved" the changes by opening and closing the token window.

Lindharin
Dragon
Posts: 668
Joined: Sat Apr 21, 2007 4:51 pm

Post by Lindharin »

Awesome introduction!

Lindharin
Dragon
Posts: 668
Joined: Sat Apr 21, 2007 4:51 pm

Post by Lindharin »

bobthedog wrote:Lots of great info here.

About the "macros not updating if you use the Edit Macro menu" bug, I have had this bug sitting around ever since the menu was introduced. And indeed, if you open and close the Edit Token window each time you change your macros, it'll make the changes work. I'll expand:

- if you edit one macro, close it, and open it again, you'll lose the changes you had made (I don't remember now if cancelling out the second time will keep the changes made the first time);
- if you edit several macros, they will all keep their changes after you open the Token window and close it;
- if you edit macros and don't make the changes permanent, running the macro will give you your old macro, not the new one. So if you were trying to fix an error and it appears to not have been fixed, make sure you "saved" the changes by opening and closing the token window.
Are you guys sure that is all still true? I started using MT 1.3 at version b39, and I've made and edited a bunch of token macros just from the selection panel. I can't stand using the macro tab of the token properties since it removes all the line breaks from the code, so I use the Edit Macro context menu choice on the buttons in the selection panel, and have never lost any code.

User avatar
Full Bleed
Demigod
Posts: 4736
Joined: Sun Feb 25, 2007 11:53 am
Location: FL

Post by Full Bleed »

bobthedog wrote:- if you edit one macro, close it, and open it again, you'll lose the changes you had made (I don't remember now if cancelling out the second time will keep the changes made the first time);
- if you edit several macros, they will all keep their changes after you open the Token window and close it;
- if you edit macros and don't make the changes permanent, running the macro will give you your old macro, not the new one. So if you were trying to fix an error and it appears to not have been fixed, make sure you "saved" the changes by opening and closing the token window.
The impersonation window is what's bugged. Edit your token from the selection window and the changes stick. If you're currently impersonating too, you'll have to depersonate then re-impersonate to have the changes show up.

Been waiting for Ryss to get back to fix this... but seeing as he's been gone almost a month, someone else might want to jump in and do it. Or, at the very least turn off editing in the Impersonation window until it is fixed.

This issue is enhanced because players tend to use the impersonate window, while gm's tend to use the selection window.
Last edited by Full Bleed on Wed Aug 20, 2008 10:05 am, edited 1 time in total.

Fobbo
Giant
Posts: 196
Joined: Wed Feb 01, 2006 2:11 pm

Post by Fobbo »

That is a fantastic break down and usage of Macros. Thank you k.fan

bobthedog
Cave Troll
Posts: 85
Joined: Sun Aug 03, 2008 7:17 pm

Post by bobthedog »

Full Bleed wrote:Not sure if b40 changes this, but the problem used to be in the impersonate window. If you do your editing from the Selection window there wasn't a problem.
Hmmm, I might have been using the Impersonate window all the time... Still, I would have assumed that they worked the same, but it looks like they don't.

Still, if anyone starts "losing code" as Lindharin put it, the solutions are listed there for reference. And k.fan's great advice to use a text editor avoids the "oh no, all the changes I had made were lost" situation, since you should have them on notepad or wherever.

User avatar
jfrazierjr
Deity
Posts: 5176
Joined: Tue Sep 11, 2007 7:31 pm

Post by jfrazierjr »

bobthedog wrote:
Full Bleed wrote:Not sure if b40 changes this, but the problem used to be in the impersonate window. If you do your editing from the Selection window there wasn't a problem.
Hmmm, I might have been using the Impersonate window all the time... Still, I would have assumed that they worked the same, but it looks like they don't.

Still, if anyone starts "losing code" as Lindharin put it, the solutions are listed there for reference. And k.fan's great advice to use a text editor avoids the "oh no, all the changes I had made were lost" situation, since you should have them on notepad or wherever.
It make perfect sense if you think about it. In coding, whenever you are getting data from something, you don't want to have to go get it every time it's called as that would be a performance hit and slow things done. So when the token is impersonated, the Impersonation panel caches the current values there to speed things up as it does not have to then go back to the token to get the current string value of each token's macros. However, what needs to happen is that when a macro is added/changed on the Selection panel, a signal needs to be sent to the Selection panel to say "Hey you! you got work to do. go find your toke and recache all of the macros again."

Think if it this way, if you called the same person 20 times a day, it would be silly to put that number into a filling cabinet with 500 other of your contacts and have to pull it out each time. Caching just makes a copy somewhere more convenient to get to and thus saves time at the expense of you have to be careful to have the code know when someone changed the phone number copy in the filling cabinet that the copy you have beside the phone needs to know it has to be updated.
I save all my Campaign Files to DropBox. Not only can I access a campaign file from pretty much any OS that will run Maptool(Win,OSX, linux), but each file is versioned, so if something goes crazy wild, I can always roll back to a previous version of the same file.

Get your Dropbox 2GB via my referral link, and as a bonus, I get an extra 250 MB of space. Even if you don't don't use my link, I still enthusiastically recommend Dropbox..

Suddry
Kobold
Posts: 19
Joined: Thu Aug 14, 2008 11:38 am

Post by Suddry »

Absolutely brilliant! Thank you for the time it took to put this together. My less-coding-proficient group members will make excellent use of this!

/applaud

User avatar
AidyBaby
Dragon
Posts: 383
Joined: Tue Feb 07, 2006 12:55 pm
Contact:

Post by AidyBaby »

Thank you for this info. Just what I needed.
D&D qualities are related inversely to those of Poker... and I love both.
http://www.yorkpoker.co.uk

User avatar
RPMiller
Demigod
Posts: 2555
Joined: Sun Jul 01, 2007 1:23 am

Post by RPMiller »

Great tutorial! Thanks for taking the time to write this out.
You're just jealous 'cause the voices only talk to me.

ImageImage

bobthedog
Cave Troll
Posts: 85
Joined: Sun Aug 03, 2008 7:17 pm

Post by bobthedog »

Oh yea, k.fan!

Re-reading your stuff I just remembered something... "slash commands" (/me /self) work in token macros, as long as you start the macro with them. So the example below would show the result only to you:

Code: Select all

/self <!--
[Variable = X]
[Property = Y]
-->
<b>Result:</b> {Variable + Property}
While the example below would say to everyone "/self Result: Z":

Code: Select all

<!--
[Variable = X]
[Property = Y]
-->
/self <b>Result:</b> {Variable + Property}
I actually have a lot of "self" macros, on my token...

Richard Weimer
Cave Troll
Posts: 62
Joined: Mon Jun 12, 2006 4:39 pm
Location: Peoria, AZ

Post by Richard Weimer »

This thread definitely needs to be Stickied, and maintained. It is a very good overview on the macro functionality of the program.

Good job!

Lindharin
Dragon
Posts: 668
Joined: Sat Apr 21, 2007 4:51 pm

Post by Lindharin »

Richard Weimer wrote:This thread definitely needs to be Stickied, and maintained.
Seconded! It's great, and I wish I had it about 4 days ago... :lol:

User avatar
kat2cute
Dragon
Posts: 297
Joined: Wed Jan 30, 2008 3:46 pm

Post by kat2cute »

If you finish updating it and add a few more screen capture images of what the code outputs look like, I'll paste a copy of your tutorial into the Maptool Documentation wiki. In fact, you should PM trevor and get access to edit the wiki also so that all the mini-tutorial steps you listed here can be organized and formatted to your liking with Wiki-style links.

I think you forgot to actually formally introduce HTML commenting, though I could have missed it seeing as there was a lot to read.
Quote from an underwater D&D fight:
Alright fighter, it's your turn. What do you do?
Fighter: What do you think I do? I FAIL MY F**KING SWIM CHECK

Post Reply

Return to “Documentation Requests/Discussion”