Updating Macro Buttons Using a Macro (Group Method): Difference between revisions

From RPTools Wiki
Jump to navigation Jump to search
No edit summary
 
(19 intermediate revisions by 6 users not shown)
Line 1: Line 1:
==Updating color of our macro buttons using DnD4e as an example==
==Updating color of our macro buttons using DnD4e as an example==
For an example I will use DnD4e powers, when a power is used it will then update the button to show this. Although this is example is for DnD4e the technique is applicable for many other systems.
For an example I will use DnD4e powers; when a power is used it will then update the button to show this. Although this example is for DnD4e the technique is applicable for many other systems.
 
Let's assume that you have macro groups named "Daily Powers" and "Encounter Powers" where we place all of our powers, and we want to set the color of the [[Macro_Button|macro button]] to blue if the power has been used. If you want another way to do this without using different groups see [[Tutorials:Macros:UpdatingMacroButtons:DnD4ePowersPrefix | Tracking Used DnD 4e Powers (Macro Prefix Method)]]
 
 
 
'''Version update:'''
This tutorial was written before 1.3b50. As of 1.3b50 you can use [[Macros:Functions:getMacroButtonIndex|getMacroButtonIndex]] to determine the index of the button that was pressed. Instead of setting/getting the properties of the button by name you can use the index of the button in place of the name, this way you will not run the risk of updating buttons with the same name.


Lets assume that you have a macro groups named "Daily Powers" and "Encounter Powers" where we place all of our powers, and we want to set the color of the [[macro button]] to blue if the power has been used. If you want another way to do this without using different groups see [[Tutorials:Macros:UpdatingMacroButtons:DnD4ePowersPrefix | Tracking Used DnD 4e Powers (Macro Prefix Method)]]


===Short Rest, resetting color of buttons in the "Encounter Powers" group===
===Short Rest, resetting color of buttons in the "Encounter Powers" group===
So first we will create a [[macro button]] called "Short Rest", for this tutorial I will assume you just create it as a [[campaign macro]] --just remember to check the [[Macros:Apply to Selected Tokens|Apply to Selected Tokens]] check mark-- you can just as easily create these as macros in [[Token:library token|library token]] macros and call them from from [[macro buttons]] on your [[Token:tokens|tokens]].
So first we will create a [[Macro_Button|macro button]] called "Short Rest", for this tutorial I will assume you just create it as a [[Introduction_to_Macro_Writing#Campaign Macros|campaign macro]] --just remember to check the [[Introduction to Macro Writing#Referencing a Token Property in a Macro|Apply to Selected Tokens]] check mark-- you can just as easily create these as macros in [[Token:library token|library token]] macros and call them from from [[Macro_Button|macro buttons]] on your [[Token|tokens]].


[[image:ShortRest1MacroButton.png]]
[[image:ShortRest1MacroButton.png]]


So create the "Short Rest" [[macro button]] and copy the following code into it.
So create the "Short Rest" [[Macro_Button|macro button]] and copy the following code into it
<source lang="mtmacro" line>
<syntaxhighlight lang="mtmacro" line>
[abort(hasImpersonated())] <!-- Abort macro if no token is impersonated -->
[abort(hasImpersonated())] <!-- Abort macro if no token is impersonated -->


Line 28: Line 34:
}]
}]
[abort(0)] <!-- Suppress output text -->
[abort(0)] <!-- Suppress output text -->
</source>
</syntaxhighlight>
The way the above macro works is by getting a list of the macros [[Macros:Functions:getMacros|getMacros()]] which will return all the labels of the [[macro buttons]] on the [[Token:current token|current token]]. Since a [[Token:token|token]] can contain multiple [[macro buttons]] with the same label the function [[Macros:Functions:getMacroIndexes|getMacroIndexes()]] is used to return the unique index of each [[macro button]] for each of the labels. Then we use [[Macros:Functions:getMacroProps|getMacroProps()]] to get the properties of the [[macro button]] in a [[Macros:string property list|string property list]]. The color of the [[macro button]] is extracted from this using [[Macros:Functions:getStrProp|getStrProp()]] and we check to see if it is "blue", if it is we also check to see if it is in the "Encounter Powers" group, and set the value of isBlue based on this. Then if isBlue is true (non zero) we use [[Macros:Functions:setMacroProps|setMacroProps()]] to change the color back to the default.  
The way the above macro works is by getting a list of the macros [[Macros:Functions:getMacros|getMacros()]] which will return all the labels of the [[Macro_Button|macro buttons]] on the [[Current Token]]. Since a [[Token|token]] can contain multiple [[Macro_Button|macro buttons]] with the same label the function [[Macros:Functions:getMacroIndexes|getMacroIndexes()]] is used to return the unique index of each [[Macro_Button|macro button]] for each of the labels. Then we use [[Macros:Functions:getMacroProps|getMacroProps()]] to get the properties of the [[Macro_Button|macro button]] in a [[Macros:string property list|string property list]]. The color of the [[Macro_Button|macro button]] is extracted from this using [[Macros:Functions:getStrProp|getStrProp()]] and we check to see if it is "blue", if it is we also check to see if it is in the "Encounter Powers" group, and set the value of isBlue based on this. Then if isBlue is true (non zero) we use [[Macros:Functions:setMacroProps|setMacroProps()]] to change the color back to the default.  


You can test this macro by dragging a [[Token:token]] onto the map and adding a [[macro button]] to it called "Something or other" in the "Encounter Powers" group and set it to blue in the creation dialog.
You can test this macro by dragging a [[Token|token]] onto the map and adding a [[Macro_Button|macro button]] to it called "Something or other" in the "Encounter Powers" group and set it to blue in the creation dialog.


[[image:ButtonSomethingOrOtherBlueGroup.png]] [[image:ButtonSomethingOrOtherDefaultGroup.png]]
[[image:ButtonSomethingOrOtherBlueGroup.png]] [[image:ButtonSomethingOrOtherDefaultGroup.png]]


===Extended Rest, resetting color of buttons starting with "Encounter Powers" or "Daily Powers"===
===Extended Rest, resetting color of buttons starting with "Encounter Powers" or "Daily Powers"===
For an extended rest we want to reset the color of any [[macro buttons]] that start with either "Encounter Powers" or "Daily Powers". So create a [[campaign macro]] called "Extended Rest" (don't forget to check the [[Macros:Apply to Selected Tokens|Apply to Selected Tokens]] check box) and copy the following code into it.
For an extended rest we want to reset the color of any [[Macro_Button|macro buttons]] that start with either "Encounter Powers" or "Daily Powers". So create a [[Introduction_to_Macro_Writing#Campaign Macros|campaign macro]] called "Extended Rest" (don't forget to check the [[Introduction to Macro Writing#Referencing a Token Property in a Macro|Apply to Selected Tokens]] check box) and copy the following code into it


<source lang="mtmacro" line>
<syntaxhighlight lang="mtmacro" line>
[abort(hasImpersonated())] <!-- Abort macro if no token is impersonated -->
[abort(hasImpersonated())] <!-- Abort macro if no token is impersonated -->


Line 59: Line 63:
}]
}]
[abort(0)] <!-- Suppress output text -->
[abort(0)] <!-- Suppress output text -->
</source>
</syntaxhighlight>


The only difference between this macro and the previous one is where it checks the group of the [[macro button]]. In the "Short Rest" [[macro button]] we had  
The only difference between this macro and the previous one is where it checks the group of the [[Macro_Button|macro button]]. In the "Short Rest" [[Macro_Button|macro button]] we had  
<source lang="mtmacro" line start=12>
<syntaxhighlight lang="mtmacro" line start=12>
     [isBlue = if(getStrProp(props, "color") == "blue" &&
     [isBlue = if(getStrProp(props, "color") == "blue" &&
                 getStrProp(props, "group") == "Encounter Powers", 1, 0)]
                 getStrProp(props, "group") == "Encounter Powers", 1, 0)]
</source>
</syntaxhighlight>
Where as in the "Extended Rest" [[macro button]] it is
Where in the "Extended Rest" [[Macro_Button|macro button]] it is
<source lang="mtmacro" line start=12>
<syntaxhighlight lang="mtmacro" line start=12>
     [isBlue = if(getStrProp(props, "color") == "blue" &&
     [isBlue = if(getStrProp(props, "color") == "blue" &&
                   matches(getStrProp(props, "group"),
                   matches(getStrProp(props, "group"),
                           "(Daily|Encounter) Powers"), 1, 0)]
                           "(Daily|Encounter) Powers"), 1, 0)]
</source>
</syntaxhighlight>
The pattern ''(Daily|Encounter) Powers'' matches both the "Daily Powers" and "Encounter Powers" strings.
The pattern ''(Daily|Encounter) Powers'' matches both the "Daily Powers" and "Encounter Powers" strings.
Hopefully from this you can see how to add powers with different durations, say you wanted to add powers that could be used once per round and place them in the "Round Group", for your "New Round" macro which resets the color you would change the lines to
Hopefully from this you can see how to add powers with different durations, say you wanted to add powers that could be used once per round and place them in the "Round Group", for your "New Round" macro which resets the color you would change the lines to
<source lang="mtmacro" line start=12>
<syntaxhighlight lang="mtmacro" line start=12>
     [isBlue = if(getStrProp(props, "color") == "blue" &&
     [isBlue = if(getStrProp(props, "color") == "blue" &&
                 getStrProp(props, "group") == "Round Powers", 1, 0)]
                 getStrProp(props, "group") == "Round Powers", 1, 0)]
</source>
</syntaxhighlight>


And for your "Short Rest" you would change it to refresh encounter and round powers.
And for your "Short Rest" you would change it to refresh encounter and round powers
<source lang="mtmacro" line start=12>
<syntaxhighlight lang="mtmacro" line start=12>
     [isBlue = if(getStrProp(props, "color") == "blue" &&
     [isBlue = if(getStrProp(props, "color") == "blue" &&
                   matches(getStrProp(props, "group"),
                   matches(getStrProp(props, "group"),
                           "(Round|Encounter) Powers"), 1, 0)]
                           "(Round|Encounter) Powers"), 1, 0)]
</source>
</syntaxhighlight>
And for your "Extended Rest" you would change it to refresh daily, encounter and round powers.
And for your "Extended Rest" you would change it to refresh daily, encounter and round powers
<source lang="mtmacro" line start=12>
<syntaxhighlight lang="mtmacro" line start=12>
     [isBlue = if(getStrProp(props, "color") == "blue" &&
     [isBlue = if(getStrProp(props, "color") == "blue" &&
                   matches(getStrProp(props, "group"),
                   matches(getStrProp(props, "group"),
                           "(Round|Encounter|Daily) Powers"), 1, 0)]
                           "(Round|Encounter|Daily) Powers"), 1, 0)]
</source>
</syntaxhighlight>
 
 


===Using Powers, or getting the blues...===
===Using Powers, or getting the blues...===
So now all that is left is to set the color of the buttons when they are used. As of 1.3b48 there is no way to determine which button has been pressed from a macro,  but what you can do is to add code like the following to your power macros.
So now all that is left is to set the color of the buttons when they are used. As of 1.3b48 there is no way to determine which button has been pressed from a macro,  but what you can do is to add code like the following to your power macros


<source lang="mtmacro" line>
<syntaxhighlight lang="mtmacro" line>
     [h: setMacroProps("Burning Hands", "color=blue")]
     [h: setMacroProps("Burning Hands", "color=blue")]
</source>
</syntaxhighlight>
Replacing the "Burning Hands" with the label of your [[macro button]].
Replacing the "Burning Hands" with the label of your [[Macro_Button|macro button]].
So lets try it, on your token create a [[macro button]] called "Sleep" in the group called "Daily Powers" and in the button place the following code
So lets try it, on your token create a [[Macro_Button|macro button]] called "Sleep" in the group called "Daily Powers" and in the button place the following code
<source lang="mtmacro" line>
<syntaxhighlight  lang="mtmacro" line>
Watch, the watch, you are getting sleepy, your eyelids are getting heavy.... [h: setMacroProps("Sleep", "color=blue")]
Watch, the watch, you are getting sleepy, your eyelids are getting heavy.... [h: setMacroProps("Sleep", "color=blue")]
</source>  
</syntaxhighlight>  
Click on the button and hopefully you should see it change to blue.
Click on the button and hopefully you should see it change to blue.


===Multiple Power Buttons with the same name===
===Multiple Power Buttons with the same name===
A word of warning though this will change the color of all buttons with that label so if you have duplicates and only want to set one (you may want to implement multi use per day powers as multiple buttons for example)
A word of warning though: the above method will change the color of all buttons with that label so if you have duplicates and only want to set one (you may want to implement multi use per day powers as multiple buttons for example).


Drag a new [[Token:token|token]] onto the map and change its name to Lib:DnD4ePowers, and create a [[macro button]] called "UseDailyPower", then copy in the following code.
Drag a new [[Token|token]] onto the map and change its name to Lib:DnD4ePowers, and create a [[Macro_Button|macro button]] called "UseDailyPower", then copy in the following code


<source lang="mtmacro" line>
<syntaxhighlight  lang="mtmacro" line>
[h: found = 0]
[h: found = 0]
[h: indexes = getMacroIndexes(macro.args)]
[h: indexes = getMacroIndexes(macro.args)]
Line 127: Line 128:
     }]
     }]
}]
}]
</source>
</syntaxhighlight>
This will loop through all of the indexes for the [[macro button]]s with the specified name searching for one that is the default color and a daily power, once it finds one it sets its color to blue and sets found=1 so no other buttons are changed (as of 1.3b48 there is no way to break out of a loop).
This will loop through all of the indexes for the [[Macro_Button|macro button]]s with the specified name searching for one that is the default color and a daily power, once it finds one it sets its color to blue and sets found=1 so no other buttons are changed (as of 1.3b48 there is no way to break out of a loop).


Now create a [[macro button]] called "Lay On Hands" and copy the following in.
Now create a [[Macro_Button|macro button]] called "Lay On Hands" and copy the following in


<source lang="mtmacro" line>
<syntaxhighlight  lang="mtmacro" line>
     Oooh tingly!
     Oooh tingly!
     [h,macro("UseDailyPower@Lib:DnD4ePowers"): "Lay On Hands"]
     [h,macro("UseDailyPower@Lib:DnD4ePowers"): "Lay On Hands"]
</source>
</syntaxhighlight>
Duplicate that a few times and then when you click on on of the buttons then one of the "Lay On Hands" buttons will turn blue.
Duplicate that a few times and then when you click on on of the buttons then one of the "Lay On Hands" buttons will turn blue.


Line 142: Line 143:
We can do that by changing the "UseDailyPower" macro we created above on the Lib:DnD4ePowers [[Token:library token|library token]].
We can do that by changing the "UseDailyPower" macro we created above on the Lib:DnD4ePowers [[Token:library token|library token]].
Change it to the following
Change it to the following


===Sorry Sir/Madam, you have already used that!===
===Sorry Sir/Madam, you have already used that!===
<source lang="mtmacro" line>
<syntaxhighlight lang="mtmacro" line>
[h: found = 0]
[h: found = 0]
[h: indexes = getMacroIndexes(macro.args)]
[h: indexes = getMacroIndexes(macro.args)]
Line 169: Line 168:
}]
}]
[abort(found)] <!-- Abort the macro if an unused power was not found -->
[abort(found)] <!-- Abort the macro if an unused power was not found -->
</source>
</syntaxhighlight>


And change the [[Token:token]]'s "Lay On Hands" macro code (don't forget to change all the duplicates too).
And change the [[Token|token]]'s "Lay On Hands" macro code (don't forget to change all the duplicates too)
<source lang="mtmacro" line>
<syntaxhighlight lang="mtmacro" line>
     [h,macro("UsePower@Lib:DnD4ePowers"): "Daily:Lay On Hands"]
     [h,macro("UsePower@Lib:DnD4ePowers"): "Daily:Lay On Hands"]
     Oooh tingly!
     Oooh tingly!
</source>
</syntaxhighlight>


Then clickity, clickity, click on the "Daily:Lay On Hands" buttons and when you have none left you should get the following dialog.
Then clickity, clickity, click on the "Daily:Lay On Hands" buttons and when you have none left you should get the following dialog


[[image:PowerUsedDialogGroup.png]]
[[image:PowerUsedDialogGroup.png]]
Line 183: Line 182:
It ain't pretty but the concept is there and you can easily expand on it to pretty it up.
It ain't pretty but the concept is there and you can easily expand on it to pretty it up.


While we are at it we should add a "UseEncounterPower" macro to Lib:DnD4ePowers.
While we are at it we should add a "UseEncounterPower" macro to Lib:DnD4ePowers
<source lang="mtmacro" line>
<syntaxhighlight lang="mtmacro" line>
[h: found = 0]
[h: found = 0]
[h: indexes = getMacroIndexes(macro.args)]
[h: indexes = getMacroIndexes(macro.args)]
Line 207: Line 206:
}]
}]
[abort(found)] <!-- Abort the macro if an unused power was not found -->
[abort(found)] <!-- Abort the macro if an unused power was not found -->
</source>
</syntaxhighlight>


You can also use this for cases where there is only a single button for a power.
You can also use this for cases where there is only a single button for a power.


You can download this part of the tutorial in in a [http://lmwcs.com/maptool/campaigns/ButtonChange2.cmpgn campaign file] which was made using MapTool 1.3b48.
You can download this part of the tutorial in in a [http://lmwcs.com/maptool/campaigns/ButtonChange2.cmpgn campaign file] which was made using MapTool 1.3b48.
[[Category:Tutorial]]

Latest revision as of 20:46, 15 March 2023

Updating color of our macro buttons using DnD4e as an example

For an example I will use DnD4e powers; when a power is used it will then update the button to show this. Although this example is for DnD4e the technique is applicable for many other systems.

Let's assume that you have macro groups named "Daily Powers" and "Encounter Powers" where we place all of our powers, and we want to set the color of the macro button to blue if the power has been used. If you want another way to do this without using different groups see Tracking Used DnD 4e Powers (Macro Prefix Method)


Version update: This tutorial was written before 1.3b50. As of 1.3b50 you can use getMacroButtonIndex to determine the index of the button that was pressed. Instead of setting/getting the properties of the button by name you can use the index of the button in place of the name, this way you will not run the risk of updating buttons with the same name.


Short Rest, resetting color of buttons in the "Encounter Powers" group

So first we will create a macro button called "Short Rest", for this tutorial I will assume you just create it as a campaign macro --just remember to check the Apply to Selected Tokens check mark-- you can just as easily create these as macros in library token macros and call them from from macro buttons on your tokens.

So create the "Short Rest" macro button and copy the following code into it

[abort(hasImpersonated())] <!-- Abort macro if no token is impersonated -->

[h,foreach(macro, getMacros()), code: {
  <!-- 
    == each label can appear more than once (i.e. more than one
    == button with same label, so we need to get all the button
    == indexes for a label
  -->

  [h,foreach(index, getMacroIndexes(macro)), code: {
    [props = getMacroProps(index)]
    [isBlue = if(getStrProp(props, "color") == "blue" &&
                 getStrProp(props, "group") == "Encounter Powers", 1, 0)]
    [h,if(isBlue): setMacroProps(index, "color=default")]
  }]
}]
[abort(0)] <!-- Suppress output text -->

The way the above macro works is by getting a list of the macros getMacros() which will return all the labels of the macro buttons on the Current Token. Since a token can contain multiple macro buttons with the same label the function getMacroIndexes() is used to return the unique index of each macro button for each of the labels. Then we use getMacroProps() to get the properties of the macro button in a string property list. The color of the macro button is extracted from this using getStrProp() and we check to see if it is "blue", if it is we also check to see if it is in the "Encounter Powers" group, and set the value of isBlue based on this. Then if isBlue is true (non zero) we use setMacroProps() to change the color back to the default.

You can test this macro by dragging a token onto the map and adding a macro button to it called "Something or other" in the "Encounter Powers" group and set it to blue in the creation dialog.

Extended Rest, resetting color of buttons starting with "Encounter Powers" or "Daily Powers"

For an extended rest we want to reset the color of any macro buttons that start with either "Encounter Powers" or "Daily Powers". So create a campaign macro called "Extended Rest" (don't forget to check the Apply to Selected Tokens check box) and copy the following code into it

[abort(hasImpersonated())] <!-- Abort macro if no token is impersonated -->

[h,foreach(macro, getMacros()), code: {
  <!-- 
    == each label can appear more than once (i.e. more than one
    == button with same label, so we need to get all the button
    == indexes for a label
  -->

  [h,foreach(index, getMacroIndexes(macro)), code: {
    [props = getMacroProps(index)]
    [isBlue = if(getStrProp(props, "color") == "blue" &&
                   matches(getStrProp(props, "group"),
                          "(Daily|Encounter) Powers"), 1, 0)]
    [h,if(isBlue): setMacroProps(index, "color=default")]
  }]
}]
[abort(0)] <!-- Suppress output text -->

The only difference between this macro and the previous one is where it checks the group of the macro button. In the "Short Rest" macro button we had

    [isBlue = if(getStrProp(props, "color") == "blue" &&
                 getStrProp(props, "group") == "Encounter Powers", 1, 0)]

Where in the "Extended Rest" macro button it is

    [isBlue = if(getStrProp(props, "color") == "blue" &&
                   matches(getStrProp(props, "group"),
                          "(Daily|Encounter) Powers"), 1, 0)]

The pattern (Daily|Encounter) Powers matches both the "Daily Powers" and "Encounter Powers" strings. Hopefully from this you can see how to add powers with different durations, say you wanted to add powers that could be used once per round and place them in the "Round Group", for your "New Round" macro which resets the color you would change the lines to

    [isBlue = if(getStrProp(props, "color") == "blue" &&
                 getStrProp(props, "group") == "Round Powers", 1, 0)]

And for your "Short Rest" you would change it to refresh encounter and round powers

    [isBlue = if(getStrProp(props, "color") == "blue" &&
                   matches(getStrProp(props, "group"),
                          "(Round|Encounter) Powers"), 1, 0)]

And for your "Extended Rest" you would change it to refresh daily, encounter and round powers

    [isBlue = if(getStrProp(props, "color") == "blue" &&
                   matches(getStrProp(props, "group"),
                          "(Round|Encounter|Daily) Powers"), 1, 0)]

Using Powers, or getting the blues...

So now all that is left is to set the color of the buttons when they are used. As of 1.3b48 there is no way to determine which button has been pressed from a macro, but what you can do is to add code like the following to your power macros

    [h: setMacroProps("Burning Hands", "color=blue")]

Replacing the "Burning Hands" with the label of your macro button. So lets try it, on your token create a macro button called "Sleep" in the group called "Daily Powers" and in the button place the following code

Watch, the watch, you are getting sleepy, your eyelids are getting heavy.... [h: setMacroProps("Sleep", "color=blue")]

Click on the button and hopefully you should see it change to blue.

Multiple Power Buttons with the same name

A word of warning though: the above method will change the color of all buttons with that label so if you have duplicates and only want to set one (you may want to implement multi use per day powers as multiple buttons for example).

Drag a new token onto the map and change its name to Lib:DnD4ePowers, and create a macro button called "UseDailyPower", then copy in the following code

[h: found = 0]
[h: indexes = getMacroIndexes(macro.args)]
[h, foreach(button, indexes), code: {
    [if(found==0), code: {
        [props = getMacroProps(button)]
        [group = getStrProp(props, "group")]
        [color = getStrProp(props, "color")]
        [if(color=="default" && group == "Daily Powers"): 
            setMacroProps(button, "color=blue")
        ]
        [if(color=="default" && group == "Daily Powers"): found=1]
    }]
}]

This will loop through all of the indexes for the macro buttons with the specified name searching for one that is the default color and a daily power, once it finds one it sets its color to blue and sets found=1 so no other buttons are changed (as of 1.3b48 there is no way to break out of a loop).

Now create a macro button called "Lay On Hands" and copy the following in

    Oooh tingly!
    [h,macro("UseDailyPower@Lib:DnD4ePowers"): "Lay On Hands"]

Duplicate that a few times and then when you click on on of the buttons then one of the "Lay On Hands" buttons will turn blue.

Fine you say but I would like to stop players using powers that are blue (or in the case of multi use powers where there are no non blue ones remaining).

We can do that by changing the "UseDailyPower" macro we created above on the Lib:DnD4ePowers library token. Change it to the following

Sorry Sir/Madam, you have already used that!

[h: found = 0]
[h: indexes = getMacroIndexes(macro.args)]
[h, foreach(button, indexes), code: {
    [if(found==0), code: {
        [props = getMacroProps(button)]
        [group = getStrProp(props, "group")]
        [color = getStrProp(props, "color")]
        [if(color=="default" && group == "Daily Powers"): 
            setMacroProps(button, "color=blue")
        ]
        [if(color=="default" && group == "Daily Powers"): found=1]
    }]
}]
<!-- if "free" one is not found then inform user they can't do it -->
[if(found==0), code: {
    [dialog("PowerUsed"):  {
        <title>Can Not Use Power</title>
        <meta name="temporary" content="true">
        You have already used [r: macro.args]
    }]
}]
[abort(found)] <!-- Abort the macro if an unused power was not found -->

And change the token's "Lay On Hands" macro code (don't forget to change all the duplicates too)

    [h,macro("UsePower@Lib:DnD4ePowers"): "Daily:Lay On Hands"]
    Oooh tingly!

Then clickity, clickity, click on the "Daily:Lay On Hands" buttons and when you have none left you should get the following dialog

It ain't pretty but the concept is there and you can easily expand on it to pretty it up.

While we are at it we should add a "UseEncounterPower" macro to Lib:DnD4ePowers

[h: found = 0]
[h: indexes = getMacroIndexes(macro.args)]
[h, foreach(button, indexes), code: {
    [if(found==0), code: {
        [props = getMacroProps(button)]
        [group = getStrProp(props, "group")]
        [color = getStrProp(props, "color")]
        [if(color=="default" && group == "Encounter Powers"): 
            setMacroProps(button, "color=blue")
        ]
        [if(color=="default" && group == "Encounter Powers"): found=1]
    }]
}]
<!-- if "free" one is not found then inform user they can't do it -->
[if(found==0), code: {
    [dialog("PowerUsed"):  {
        <title>Can Not Use Power</title>
        <meta name="temporary" content="true">
        You have already used [r: macro.args]
    }]
}]
[abort(found)] <!-- Abort the macro if an unused power was not found -->

You can also use this for cases where there is only a single button for a power.

You can download this part of the tutorial in in a campaign file which was made using MapTool 1.3b48.