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

From RPTools Wiki
Jump to navigation Jump to search
m (Unifying Current Token red link.)
No edit summary
 
(11 intermediate revisions by 4 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.


For the first set up lets assume that we have prefixed our powers with "Daily:" for daily powers and "Encounter:" for encounter 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 having to place "Daily:" or "Encounter:" in front of your power see [[Tutorials:Macros:UpdatingMacroButtons:DnD4ePowersGroup | Tracking Used DnD 4e Powers (Macro Group Method)]]
For the first set up let's assume that we have prefixed our powers with "Daily:" for daily powers and "Encounter:" for encounter 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 having to place "Daily:" or "Encounter:" in front of your power see [[Tutorials:Macros:UpdatingMacroButtons:DnD4ePowersGroup | Tracking Used DnD 4e Powers (Macro Group Method)]]




'''Version update:'''  
'''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.
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.




===Short Rest, resetting color of buttons starting with "Encounter:"===
===Short Rest, resetting color of buttons starting with "Encounter:"===
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 33: Line 33:
}]
}]
[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 [[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 the label of the button starts with "Encounter:" 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 the label of the button starts with "Encounter:" 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 "Encounter:Something or other" 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 "Encounter:Something or other" and set it to blue in the creation dialog.


[[image:ButtonSomethingOrOtherBlue.png]] [[image:ButtonSomethingOrOtherDefault.png]]
[[image:ButtonSomethingOrOtherBlue.png]] [[image:ButtonSomethingOrOtherDefault.png]]


===Extended Rest, resetting color of buttons starting with "Encounter:" or "Daily:"===
===Extended Rest, resetting color of buttons starting with "Encounter:" or "Daily:"===
For an extended rest we want to reset the color of any [[macro buttons]] that start with either "Encounter:" or "Daily:". 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:" or "Daily:". 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 63: Line 61:
}]
}]
[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 prefix 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 prefix 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" &&
                   matches(macro, "Encounter:.*"),  1, 0)]
                   matches(macro, "Encounter:.*"),  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(macro, "(Daily|Encounter):.*"),  1, 0)]
                   matches(macro, "(Daily|Encounter):.*"),  1, 0)]
</source>
</syntaxhighlight>
The pattern ''(Daily|Encounter):.*'' matches a string that starts with either "Daily:" or "Encounter:".  
The pattern ''(Daily|Encounter):.*'' matches a string that starts with either "Daily:" or "Encounter:".  
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 you prefix them with "Round:", 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 you prefix them with "Round:", 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" &&
                   matches(macro, "Round:.*"),  1, 0)]
                   matches(macro, "Round:.*"),  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(macro, "(Round|Encounter):.*"),  1, 0)]
                   matches(macro, "(Round|Encounter):.*"),  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(macro, "(Round|Encounter|Daily):.*"),  1, 0)]
                   matches(macro, "(Round|Encounter|Daily):.*"),  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("Encouner:Burning Hands", "color=blue")]
     [h: setMacroProps("Encouner:Burning Hands", "color=blue")]
</source>
</syntaxhighlight>
Replacing the "Encounter:Burning Hands" with the label of your [[macro button]].
Replacing the "Encounter:Burning Hands" with the label of your [[Macro_Button|macro button]].
So lets try it, on your token create a [[macro button]] called "Daily:Sleep" and in the button place the following code
So lets try it, on your token create a [[Macro_Button|macro button]] called "Daily:Sleep" 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("Daily:Sleep", "color=blue")]
Watch, the watch, you are getting sleepy, your eyelids are getting heavy.... [h: setMacroProps("Daily: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 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)
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 "UsePower", then copy in the following code.
Drag a new [[Token:token|token]] onto the map and change its name to Lib:DnD4ePowers, and create a [[Macro_Button|macro button]] called "UsePower", 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 124: Line 119:
     }]
     }]
}]
}]
</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, 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, 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 "Daily:Lay On Hands" and copy the following in.
Now create a [[Macro_Button|macro button]] called "Daily:Lay On Hands" and copy the following in


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


Line 139: Line 134:
We can do that by changing the "UsePower" macro we created above on the Lib:DnD4ePowers [[Token:library token|library token]].
We can do that by changing the "UsePower" 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 162: Line 155:
}]
}]
[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 "Daily:Lay On Hands" macro code (don't forget to change all the duplicates too).
And change the [[Token:token]]'s "Daily: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:PowerUsedDialog.png]]
[[image:PowerUsedDialog.png]]

Latest revision as of 16:54, 14 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.

For the first set up let's assume that we have prefixed our powers with "Daily:" for daily powers and "Encounter:" for encounter 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 having to place "Daily:" or "Encounter:" in front of your power see Tracking Used DnD 4e Powers (Macro Group 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 starting with "Encounter:"

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" &&
                   matches(macro, "Encounter:.*"),  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 the label of the button starts with "Encounter:" 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 "Encounter:Something or other" and set it to blue in the creation dialog.

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

For an extended rest we want to reset the color of any macro buttons that start with either "Encounter:" or "Daily:". 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(macro, "(Daily|Encounter):.*"),  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 prefix of the macro button. In the "Short Rest" macro button we had

    [isBlue = if(getStrProp(props, "color") == "blue" &&
                   matches(macro, "Encounter:.*"),  1, 0)]

Where in the "Extended Rest" macro button it is

    [isBlue = if(getStrProp(props, "color") == "blue" &&
                   matches(macro, "(Daily|Encounter):.*"),  1, 0)]

The pattern (Daily|Encounter):.* matches a string that starts with either "Daily:" or "Encounter:". 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 you prefix them with "Round:", for your "New Round" macro which resets the color you would change the lines to

    [isBlue = if(getStrProp(props, "color") == "blue" &&
                   matches(macro, "Round:.*"),  1, 0)]

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

    [isBlue = if(getStrProp(props, "color") == "blue" &&
                   matches(macro, "(Round|Encounter):.*"),  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(macro, "(Round|Encounter|Daily):.*"),  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("Encouner:Burning Hands", "color=blue")]

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

Watch, the watch, you are getting sleepy, your eyelids are getting heavy.... [h: setMacroProps("Daily: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 "UsePower", then copy in the following code

[h: found = 0]
[h: indexes = getMacroIndexes(macro.args)]
[h, foreach(button, indexes), code: {
    [if(found==0), code: {
        [color = getStrProp(getMacroProps(button), "color")]
        [if(color=="default"): setMacroProps(button, "color=blue")]
        [if(color=="default"): 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, 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 "Daily:Lay On Hands" and copy the following in

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

Duplicate that a few times and then when you click on on of the buttons then one of the "Daily: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 "UsePower" 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: {
        [color = getStrProp(getMacroProps(button), "color")]
        [if(color=="default"): setMacroProps(button, "color=blue")]
        [if(color=="default"): 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:token's "Daily: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.

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.