RPTools.net

Discussion and Support

Skip to content

It is currently Tue May 21, 2013 4:47 am 






Reply to topic  [ 55 posts ]  Go to page 1, 2, 3, 4  Next

Previous topic | Next topic 

  Print view

Author Message
 Offline
Great Wyrm
 
Joined: Sun Jun 22, 2008 6:53 pm
Posts: 1961
Location: Melbourne, Australia
 Post subject: Tutorial: Macro Dialogs and Frames
PostPosted: Wed Dec 03, 2008 4:24 am 
An Introduction to MapTool Macro Dialogs and Frames

Please note I will be using CSS and HTML in this tutorial but I
will not really be explaining them, if you need a refresher on
either a search on google will point you to many resources that
do a better job than I could

This post refers to functionality in 1.3 b48 or newer

The [dialog(): { }] and [frame(): { } ] "roll types" create a new
dialog or frame where all the output from the commands within the
{} will be displayed.
dialog create a dialog box that hovers over other windows.
frame creates a frame that can be docked like the other maptool
windows.
The dialog and frame windows can be used to display HTML and rolls
the same as the chat output window.

This tutorial starts with the standard blank campaign you get when
you start MapTool, anything else we need we will add along the way.

First steps
So lets jump in and create your first dialog, you can use the code
below to create a dialog.
Code:
[dialog("Test"): {
  Your first dialog!
}]


Image

I know its pretty boring but before we start adding more to it
lets create a frame so that you can see the difference
Code:
[dialog("Test"): {
  Your first dialog!
}]



Image

And a picture of your first frame docked with the other MapTool windows.

Image

Back to the dialog you can spice it up a little with some dice rolls
and HTML formatting.
Code:
[dialog("Test"): {
  <b>1d4</b> -> [1d4]<br>
  <b>1d6</b> -> [1d6]<br>
  <b>1d8</b> -> [1d8]<br>
  <b>1d10</b> -> [1d10]<br>
  <b>1d12</b> -> [1d12]<br>
  <b>1d20</b> -> [1d20]<br>
  <b>1d100</b> -> [1d100]<br>
}]

This will create a dialog box with some HTML formatting and dice rolls.
The dice rolls will have all the tooltips that you would normally get
in the chat output.

Still the title is boring (it defaults to the name of the dialog).
You can use the HTML <title> tag to change the title. Run the
code below, there is no need to close the dialog from the code
above.
Code:
[dialog("Test"): {
  <html>
    <head>
      <title>Dice Roll Dialog</title>
    </head>
    <body>
      <b>1d4</b> -> [1d4]<br>
      <b>1d6</b> -> [1d6]<br>
      <b>1d8</b> -> [1d8]<br>
      <b>1d10</b> -> [1d10]<br>
      <b>1d12</b> -> [1d12]<br>
      <b>1d20</b> -> [1d20]<br>
      <b>1d100</b> -> [1d100]<br>
    </body>
  </html>
}]


Image

Notice that the dialog command did not open a new dialog window,
instead it replaced the contents of the dialog you had open. When
you use [dialog()] with the name of a dialog that already exists
the contents of that dialog are replaced, ([frame()] works the
same way).

You can use this behavior to update your dialogs.
Create a token called Lib:Test with a macro called Test
Copy the following code into the Test macro.
Code:
[dialog("Test"): {
  <html>
    <head>
      <title>Dice Roll Dialog</title>
    </head>
    <body>
      <b>1d4</b> -> [1d4]<br>
      <b>1d6</b> -> [1d6]<br>
      <b>1d8</b> -> [1d8]<br>
      <b>1d10</b> -> [1d10]<br>
      <b>1d12</b> -> [1d12]<br>
      <b>1d20</b> -> [1d20]<br>
      <b>1d100</b> -> [1d100]<br>
      <br>
      [macroLink("Refresh", "Test@Lib:Test")]
    </body>
  </html>
}]


Image

The above macro uses the macroLink() function to create a link
that will call Test on Lib:Test when ever it is clicked (which
will update the dialog with new rolls).


The above would be really useful if you needed a window that provided
you with a bunch of dice rolls all the time. But I assume that is not
what most people will want to do with the dialogs.

Drag another token out on to the map, and fill in the token properties.
We can create a simple character sheet with a dialog.
On the Lib:Test token create a macro called CharSheet and paste the
following code into it.
Code:
[h: propNames = "Strength, Dexterity, Constitution, Intelligence, Wisdom, Charisma"]
[dialog("CharSheetTest"): {
  <html>
    <head>
      <title>Character Sheet</title>
    </head>
    <body>
      <table>
        [foreach(prop, propNames, ""), code: {
          <tr>
            <td>[r: prop]</td>
            <td>[r: getProperty(prop)]</td>
          </tr>
        }]
      </table>
    </body>
  </html>
}]

On the new token that you placed on the map create a macro called
CharSheet and paste the following into it.
Code:
[macro("CharSheet@Lib:Test"): ""]
[abort(0)]

Click on the new macro button

Image


Last edited by Craig on Wed Dec 03, 2008 6:48 am, edited 2 times in total.

Top
 Profile  
 
 Offline
Great Wyrm
 
Joined: Sun Jun 22, 2008 6:53 pm
Posts: 1961
Location: Melbourne, Australia
 Post subject:
PostPosted: Wed Dec 03, 2008 4:24 am 
Again we are not going to set the world on fire with this character sheet
dialog. Lets spice it up a little, I will show you how to use some CSS for
formating.

To use CSS you insert a line like the following into the HTML to be displayed
Code:
    <link rel='stylesheet' type='text/css' href='myCSS@Lib:Test'></link>

Although you can (and probably should) use the getMacroLocation() function to
make sure it comes from the same Lib: token as the macro. So,
Code:
    <link rel='stylesheet' type='text/css' href='myCSS@[r: getMacroLocation()]'></link>


Edit the CharSheet macro on the Lib:Test token and paste in the following.
Code:
[h: propNames = "Strength, Dexterity, Constitution, Intelligence, Wisdom, Charisma"]
[dialog("CharSheetTest"): {
  <html>
    <head>
      <link rel="stylesheet" type="text/css" href="CharSheet_css@[r: getMacroLocation()]">
      <title>Character Sheet</title>
    </head>
    <body>
      <table id="stats">
        <tr>
          <th>Name</th>
          <th>Score</th>
        </tr>
        [h: class = "oddRow"]
        [foreach(prop, propNames, ""), code: {
          <tr class="[r:class]">
            <td>[r: prop]</td>
            <td>[r: getProperty(prop)]</td>
          </tr>
          [h: class = if(class=="oddRow", "evenRow", "oddRow")]
        }]
      </table>
    </body>
  </html>
}]


Also create a new macro button on Lib:Test called CharSheet_css and paste
the following CSS code into it.
Code:
.oddRow { background-color: #FFFFFF }
.evenRow { background-color: #EEEEAA }
#stats th { background-color: #113311; color: #FFFFFF }


Click on the CharSheet macro button on your token.

Image

Getting better... Lets make some more changes.

Change he CharSheet macro on Lib:Test to
Code:
[h: propNames = "Strength, Dexterity, Constitution, Intelligence, Wisdom, Charisma"]
[dialog("CharSheetTest"): {
  <html>
    <head>
      <link rel="stylesheet" type="text/css" href="CharSheet_css@[r: getMacroLocation()]">
      <title>Character Sheet</title>
    </head>
    <body>
      <table>
        <tr>
          <td>
            <img src='[r: getTokenImage(100)]'></img>
          </td>
          <td>
            <table id="stats">
              <tr>
                <th>Name</th>
                <th>Score</th>
              </tr>
              [h: class = "oddRow"]
              [foreach(prop, propNames, ""), code: {
                <tr class="[r:class]">
                  <td>[r: prop]</td>
                  <td>[r: getProperty(prop)]</td>
                </tr>
                [h: class = if(class=="oddRow", "evenRow", "oddRow")]
              }]
            </table>
          </td>
        </tr>
      </table>
      <hr>
      <table>
        <tr>
          <th>Hit Points:</th>
          <td>[r: HP]</td>
          <th>Armor Class:</th>
          </td>[r: AC]</td>
        </tr>
      <table>
    </body>
  </html>
}]


Image

Looks much better already!

Ok in Edit->Campaign Properties, Token Properties Tab, Basic Token type,
add the following properties
  • *@MaxHP
  • *@XP
  • *@NextLevelXP

Then edit your token and some values to your new properties.

Time to create a new macro on the Lib:Test called TrafficLightBar and paste
the following code into it.
Code:
<!-- ======================================================================
     ====
     ==== Outputs a red/yellow/green bar
     ====
     ==== Parameters (accepts a string property list with following keys)
     ====
     ====   MaxLen - Maximum length of status bar.
     ====   MaxValue - The "Full" value for the bar.
     ====   Value - The current value for the bar.
     ====   Label - The label for the bar.
     ====
     ====================================================================== -->
<!-- Set up the colors for our "Traffic Lights" -->
[h: r0=200] [h: g0=200] [h: b0=200]
[h: r1=200] [h: g1=0]   [h: b1=0]
[h: r2=255] [h: g2=140] [h: b2=0]
[h: r3=0]   [h: g3=200] [h: b3=0]
[h: MaxLen=getStrProp(macro.args, "MaxLen")]
[h: MaxValue=getStrProp(macro.args, "MaxValue")]
[h: Value=getStrProp(macro.args, "Value")]
[h: Label=getStrProp(macro.args, "Label")]
[h: Len=max(min(round(Value*MaxLen/MaxValue+0.4999),MaxLen),0)]
[h: Len=if(Value>=MaxValue,MaxLen, Len)]
[h: c=min(round(Value*3/MaxValue+0.4999),3)]
[h: col=min(max(Len,0),1)*c]
[h: r=eval("r"+col)] [h: g=eval("g"+col)] [h: b=eval("b"+col)]
<table>
  <tr>
    <td><span title="{Value}/{MaxValue}">{Label}</span></td>
    <td style="background-color: rgb({r},{g},{b})">
      <span title="{Value}/{MaxValue}">[c(Len, ""),r: "&nbsp;"]</span>
    </td>
    [if(MaxLen-Len>0), code: {
      <td style="background-color: rgb({r0},{g0},{b0})">
        <span title="{Value}/{MaxValue}">[c(MaxLen-Len,""),r: "&nbsp;"]</span>
      </td>
    }]
  </tr>
</table>


Create another macro on Lib:Test called StatusBar and paste the following code
into it.
Code:
<!-- ======================================================================
     ====
     ==== Outputs a "progress" bar
     ====
     ==== Parameters (accepts a string property list with following keys)
     ====
     ====   MaxLen - Maximum length of status bar.
     ====   MaxValue - The "Full" value for the bar.
     ====   Value - The current value for the bar.
     ====   Label - The label for the bar.
     ====   Color - R,G,B color
     ====
     ====================================================================== -->
[h: r0=200] [h: g0=200] [h: b0=200]
[h: MaxLen=getStrProp(macro.args, "MaxLen")]
[h: MaxValue=getStrProp(macro.args, "MaxValue")]
[h: Value=getStrProp(macro.args, "Value")]
[h: Color=getStrProp(macro.args, "Color")]
[h: Label=getStrProp(macro.args, "Label")]
[h: r1=listGet(Color,0)]
[h: g1=listGet(Color,1)]
[h: b1=listGet(Color,2)]
[h: Len=max(min(round(Value*MaxLen/MaxValue+0.4999),MaxLen),0)]
[h: c=min(round(Value/MaxValue+0.4999),1)]
[h: col=min(max(Len,0),1)*c]
[h: r=eval("r"+col)] [h: g=eval("g"+col)] [h: b=eval("b"+col)]
[h: r=eval("r"+col)] [h: g=eval("g"+col)] [h: b=eval("b"+col)]
<table>
  <tr>
    <td><span title="{Value}/{MaxValue}">{Label}</span></td>
    <td style="background-color: rgb({r},{g},{b})">
      <span title="{Value}/{MaxValue}">[c(Len, ""),r: "&nbsp;"]</span>
    </td>
    [if(MaxLen-Len>0), code: {
      <td style="background-color: rgb({r0},{g0},{b0})">
        <span title="{Value}/{MaxValue}">[c(MaxLen-Len,""),r: "&nbsp;"]</span>
      </td>
    }]
  </tr>
</table>



I am really going to gloss over the previous two functions a bit as they are
not important to understanding how to use dialogs or frames, but so you know
what they do TrafficLightBar creates a red/yellow/green bar where the color
is based on how full the bar is. StatusBar just creates a bar that is one color.

Just a quick point for those who may not know this already, but when you
call a macro with [macro("blah"): arguments] the arguments are available in
the macro in the variable macro.args. To return a value from the macro you
read the variable macro.return, the calling macro can then read macro.return
to get this value.

Then we change the CharSheet macro on Lib:Test to
Code:
[h: propNames = "Strength, Dexterity, Constitution, Intelligence, Wisdom, Charisma"]
[dialog("CharSheetTest"): {
  <html>
    <head>
      <link rel="stylesheet" type="text/css" href="CharSheet_css@[r: getMacroLocation()]">
      <title>Character Sheet</title>
    </head>
    <body>
      <table>
        <tr>
          <td>
            <img src='[r: getTokenImage(100)]'></img>
          </td>
          <td>
            <table id="stats">
              <tr>
                <th>Name</th>
                <th>Score</th>
              </tr>
              [h: class = "oddRow"]
              [foreach(prop, propNames, ""), code: {
                <tr class="[r:class]">
                  <td>[r: prop]</td>
                  <td>[r: getProperty(prop)]</td>
                </tr>
                [h: class = if(class=="oddRow", "evenRow", "oddRow")]
              }]
            </table>
          </td>
        </tr>
      </table>
      <hr>
      <table>
        <tr>
          <td>
            [h: hpBarArgs = strformat("MaxLen=50; Value=%{HP}; MaxValue=%{MaxHP}; Label=HP")]
            [macro("TrafficLightBar@this"): hpBarArgs]
          </td>
        </tr>
        <tr>
          <td>
            [h: hpBarArgs = strformat("MaxLen=50; Value=%{XP}; MaxValue=%{NextLevelXP}; Label=XP; Color=120,120,255")]
            [macro("StatusBar@this"): hpBarArgs]
          </td>
        </tr>
      <table>
    </body>
  </html>
}]



Click on the CharSheet macro button on your token again and you will have a
new character sheet.

Image

The above example uses one of the new functions in b48 strformat() which
allows you to insert variables in a string using the %{var} syntax. It also
has other flags that can be used to format variable output, see the
b48 macro addition reference thread for more information.


Last edited by Craig on Wed Dec 03, 2008 4:28 am, edited 1 time in total.

Top
 Profile  
 
 Offline
Great Wyrm
 
Joined: Sun Jun 22, 2008 6:53 pm
Posts: 1961
Location: Melbourne, Australia
 Post subject:
PostPosted: Wed Dec 03, 2008 4:24 am 
Lets leave the character sheet at this for the moment and move on to a new
example.

Edit->Campaign Properties, Token Properties Tab, Basic Token type,
add the following properties
  • Weapons
  • Items

We are going to store our weapons in a string property list with the folowing
keys.
  • NumWeapons - The number of weapons in our property list.
  • UsingWeapon - The weapon we are currently using.
  • WeaponXName - The name of weapon number X
  • WeaponXDamage - The damage of weapon number X
  • WeaponXBonus - The bonus of weapon number X
We could add a lot more, but lest keep it semi simple for this post.

The first thing we need is a way to enter weapons, we could use the input()
function but since this is a tutorial on frames and dialogs, I should probably
show you how to do it in a dialog.

But first we need to do some set up, when the player creates a new weapon we
will need to get NumWeapons add 1 to it, save it back to the property and use
that number (lets not worry about what happens if a player cancels the entry
of the weapon as we are not really that worried if we have gaps in our
numbering scheame). One problem is though what do we do first time around
snce the property list would be empty so trying to use the token property
Weapons in strProp*() functions would result in the user being prompted for
a value. We could add a default value in the campaing for the token, but
there are also other methods.
One thing we can do is use the isPropertyEmpty() function to check if the
property is empty and if so use a initial value for it, or the
getProperty() function that will just return an empty string ("") not
prompt if there is no property.

So lets create a macro that returns the number of a new weapon. Create
a macro called NextWeaponNumber and then paste the following code into it.
Code:
<!--
  Returns the number for the next weapon as well as updating the
  the counter.
  -->

<!-- If Weapons token property is empty set it to a default value -->
[h,if(isPropertyEmpty("Weapons")): Weapons = "NumWeapons=0;"]

[h: numWeapons = getStrProp(Weapons, "NumWeapons") + 1]

<!-- Now update our property -->
[h: Weapons = setStrProp(Weapons, "NumWeapons", numWeapons)]

<!-- Finally set out return value -->
[h: macro.return = numWeapons]


You can test it by running running the following code from chat a few times
Code:
[macro("NextWeaponNumber@Lib:Test"): ""] [macro.return]

When you are done you can reset the weapon count simply by editing the token
properties and clearing out the text for weapons.

Lets also make a macro called AddWeapon which takes a property list with the
following keys
  • Name
  • Damage
  • Bonus
  • Number
And adds or updates the weapon in the string property list.
Code:
<!--
  Adds a weapon to the Weapons property list
 
  Parameters (in a string property list)
 
  Name = Name of Weapon
  Damage = Damage Weapon does
  Bonus = Bonus of Weapon
  Number = The index number of the Weapon
-->
[h: num = getStrProp(macro.args, "Number")]
[h: damage = getStrProp(macro.args, "Damage")]
[h: name = getStrProp(macro.args, "Name")]
[h: bonus = getStrProp(macro.args, "Bonus")]
[h: Weapons = setStrProp(Weapons, strformat("Weapon%{num}Name"), name)]
[h: Weapons = setStrProp(Weapons, strformat("Weapon%{num}Damage"), damage)]
[h: Weapons = setStrProp(Weapons, strformat("Weapon%{num}Bonus"), bonus)]


You can test this macro too by a little typing at the command line.
Code:
[macro("AddWeapon@Lib:Test"): "Number=1; Damage=1d8; Name=LongSword; Bonus=0"]


Look at the Weapons property and see how its built up our string propety list
for us. It wont have modified NumWeapons but that is ok we are going to assume
that NextWeaponNumber is always used before adding a new weapon. Before clearing
out the Weapons property to reset it lets write a function to retrieve a
weapon.

Create a macro called GetWeapon on your Lib:Test token and paste the following
into it.
Code:
<!--
  Retrieves a weapon from the Weapons Property list.

  Parameters
    Weapon Number

  Returns
    A string property list with following keys
      Name = Name of Weapon
      Damage = Damage Weapon does
      Bonus = Bonus of Weapon
      Number = The index number of the Weapon
    If the weapon is not found then an empty string ("") is returned.
 -->
[h: num = macro.args]
[h: damage = getStrProp(Weapons, strformat("Weapon%{num}Damage"))]
[h: name = getStrProp(Weapons, strformat("Weapon%{num}Name"))]
[h: bonus = getStrProp(Weapons, strformat("Weapon%{num}Bonus"))]
[h, if(name == ""):
   macro.return = ""
;
   macro.return = strformat("Number=%{num}; Damage=%{damage}; Bonus=%{bonus}; Name=%{name}")
]


Test it with
Code:
[h, macro("GetWeapon@Lib:Test"): 1] [macro.return]


Lets add a way to delete items. Create a macro called DeleteWeapon and paste
the following code.

Code:
<!-- ============================================================ -->
<!-- ============================================================ -->
<!-- ============================================================ -->
<!--
  Deletes a weapon from the Weapons property List.

  Parameters
    The weapon number
-->
[h: num = macro.args]
[h: Weapons = deleteStrProp(Weapons, strformat("Weapon%{num}Damage"))]
[h: Weapons = deleteStrProp(Weapons, strformat("Weapon%{num}Name"))]
[h: Weapons = deleteStrProp(Weapons, strformat("Weapon%{num}Bonus"))]


One more "setup" function then we should be good to go.
Lets create a function that returns a string list of all the item numbers
(remember we can have gaps because a user could cancel the addition of the
item after calling NextWeaponNumber or they could delete a weapon).
Create a macro on Lib:Test called GetWeaponNumbers
Code:
<!--
  Gets a string list of the valid weapon numbers
-->
<!-- If Weapons token property is empty set it to a default value -->
[h,if(isPropertyEmpty("Weapons")): Weapons = "NumWeapons=0;"]

[h: maxNum = getStrProp(Weapons, "NumWeapons")]
[h: wnumList=""]
[h,c(maxNum), code: {
  [h: wnum = roll.count+1]
  [h: name = getStrProp(Weapons, strformat("Weapon%{wnum}Name"))]
  [if(name != ""):
    wnumList = listAppend(string(wnumList), string(wnum))
  ]
}]
[h: macro.return = wnumList]

The string() around the arguments in listAppend() is to convert the
arguments to strings, as of b48 listAppend() seems to have problems
with arguments that could be interpreted as numbers.


So now we can get back to the dialogs. Lets create a dialog to edit weapons.
Create a macro on your Lib:Test called EditWeaponDialog and paste the following
into it.
Code:
[dialog("weaponInput", "undecorated=1"): {
  [h: weaponNum = getStrProp(macro.args, "Number")]
  [h: name = getStrProp(macro.args, "Name")]
  [h: bonus = getStrProp(macro.args, "Bonus")]
  [h: damage = getStrProp(macro.args, "Damage")]
  <!-- If we do not have a weapon number grab the next one -->
  [h, if(weaponNum == ""), code: {
    [h,macro("NextWeaponNumber@this"): ""]
    [h: weaponNum = macro.return]
  }]
  <html>
    <head>
      <title>Edit Weapon Dialog</title>
      <meta name="input" content="true">
    </head>
    <body>
      <form name="weaponInput" action="[r:macroLinkText('AddWeapon@Lib:Test')]">
        <table>
          <tr>
            <th>
              <label for="Name">Weapon Name</label>
            </th>
            <td>
              <input type="text" name="Name" value="[r: name]"></input> <br>
            </td>
          </tr>
          <tr>
            <th>
              <label for="Damage">Weapon Damage</label>
            </th>
            <td>
              <input type="text" name="Damage" value="[r: damage]"></input> <br>
            </td>
          </tr>
          <tr>
            <th>
              <label for="Bonus">Weapon Bonus</label>
            </th>
            <td>
              <input type="text" name="Bonus" value="[r: bonus]"></input>
            </td>
          </tr>
          <tr>
        <!-- hidden input with the weapon number -->
        <input type="hidden" name="Number" value="[r: weaponNum]"></input>

        <input type="submit" name="Save" value="Save"> </input>
      </form>
    </body>
  </html>
}]


[img]http://lmwcs.com/maptool/images/DialogTut/EditWeaponDialog1.png[/img]


A Couple of things to notice, for the second argument to dialog() I have
undecorated=1. This is the same as using <meta name="input" content="1">.
Unfortionately the meta tag option has a bug at the moment so for now
you should use "undecorated=1", when I submit the patch to fix the
meta tag either option will work. The second thing to note is @this will
not work in a macro link, so I build the @ portion of the macro to
call when the form is submitted.

The action=... portion of the form tag specifies which macro to call when
any submit button is pushed for the form. If the dialog is specified as
a input dialog, the close button down the bottom is not displayed and when
any form on the dialog is submitted it is closed.

The arguments to the macro that is called when the form is submitted is
a string property list with the names of the input fields as the keys and
the entered value as the values. Since I named all my inputs the same
as the keys in the parameter for the AddWeaponMacro I can call that
straight from the submit action on the form (some times is seems like
I almost know what I am doing).

The only problem is our edit weapon is kinda plain compared to our character
sheet so time to add a little bling.

Change your EditWeaponDialog button on Lib:Test to
Code:
[dialog("weaponInput", "undecorated=1"): {
  [h: weaponNum = getStrProp(macro.args, "Number")]
  [h: name = getStrProp(macro.args, "Name")]
  [h: bonus = getStrProp(macro.args, "Bonus")]
  [h: damage = getStrProp(macro.args, "Damage")]
  <!-- If we do not have a weapon number grab the next one -->
  [h, if(weaponNum == ""), code: {
    [h,macro("NextWeaponNumber@this"): ""]
    [h: weaponNum = macro.return]
  }]
  <html>
    <head>
      <title>Edit Weapon Dialog</title>
      <meta name="input" content="true">
      <link rel="stylesheet" type="text/css" href="EditWeapon_css@[r: getMacroLocation()]">
    </head>
    <body>
      <form name="weaponInput" action="[r:macroLinkText('AddWeapon@Lib:Test')]">
        <table>
          <tr>
            <td>
              <table>
                <tr>
                  <th>
                    <label for="Name">Weapon Name</label>
                  </th>
                  <td>
                    <input type="text" name="Name" value="[r: name]">
                    </input> <br>
                  </td>
                </tr>
                <tr>
                  <th>
                    <label for="Damage">Weapon Damage</label>
                  </th>
                  <td>
                    <input type="text" name="Damage" value="[r: damage]">
                    </input> <br>
                  </td>
                </tr>
                <tr>
                  <th>
                    <label for="Bonus">Weapon Bonus</label>
                  </th>
                  <td>
                    <input type="text" name="Bonus" value="[r: bonus]">
                    </input>
                  </td>
                </tr>
              </table>
            </td>
            <td>
              <img src='[r: getTokenImage(100)]'></img>
            </td>
          </tr>
        </table>
        <!-- hidden input with the weapon number -->
        <input type="hidden" name="Number" value="[r: weaponNum]">
        </input>
        <input id="saveButton" type="submit" name="Save" value="Save">
        </input>
      </form>
    </body>
  </html>
}]


And add EditWeapon_css to Lib:Test that contains
Code:
body {
   background-color: #CCBBBB
}


And you might as well add a AddWeapon button to your Token that contains
Code:
[macro("EditWeaponDialog@Lib:Test"): "" ]
[abort(0)]


Now our dialog looks like

Image

Ok now lets make a quick dialog to display our weapons. Create a new
macro on your Lib:Test called ViewWeapons and paste in the following
Code:
[dialog("Weapons"): {
  <html>
    <head>
      <title>Weapons</title>
      <link rel="stylesheet" type="text/css" href="ViewWeapon_css@[r: getMacroLocation()]">
    </head>
    <body>
      [h,macro("GetWeaponNumbers@this"): ""]
      [h: wpList = macro.return]
      <table>
        [foreach(weapon, wpList, ""), code: {
          [h,macro("GetWeapon@this"): weapon]
          [h: wProp = macro.return]
          <tr class="WeaponName">
            <th>
              [r: getStrProp(wProp, "Name")]
            </th>
          </tr>
          <tr>
            <th>Damage</th>
            <td>[r: getStrProp(wProp, "Damage")]</td>
            <th>Bonus</th>
            <td>[r: getStrProp(wProp, "Bonus")]</td>
          </tr>
        }]
      </table>
    </body>
  </html>
}]


For good measure create a macro button called ViewWeapon_css on Lib:Test
paste in the following.
Code:
.WeaponName {
    background-color: #55AA55;
    color: white;
    text-align: center;
}


Add a button to your token called ViewWeapons which contains
Code:
[macro("ViewWeapons@Lib:Test"): ""]
[abort(0)]

And this is what it looks like

Image


* Edited to correct syntax errors


Last edited by Craig on Tue Dec 16, 2008 11:45 am, edited 2 times in total.

Top
 Profile  
 
 Offline
Great Wyrm
 
Joined: Sun Jun 22, 2008 6:53 pm
Posts: 1961
Location: Melbourne, Australia
 Post subject:
PostPosted: Wed Dec 03, 2008 4:25 am 
Up until now I havent talked at all about frames, but don't worry , change
[dialog(...] to [frame(...] above and it will work (except you cant have
a frame that closes when you submit a form, what would be the point?).

But lets make some final changes to show some frames, I am going to make
all of these in one go as everything in them has been discussed previously
in this post.

First we are going to completely change the CharSheet macro on Lib:Test to
Code:
[frame("CharSheet"): {
  [h: page = getStrProp(macro.args, "Page")]
  [h,if(page==""): page="Main"]
  <html>
    <head>
      <title>Character Sheet</title>
      <link rel="stylesheet" type="text/css" href="CharSheet_css@[r: getMacroLocation()]">
    </head>
    <body>
      [macro("CharSheetHeader@this"): page]
      <br>
      [macro("CharSheet"+page+"@this"): ""]
    </body>
  </html>
}]


Create CharSheetHeader on Lib:Test
Code:
[h: currentPage = macro.args]
[h: pages = "Main,Weapons"]
<table>
  <tr>
    [foreach(page, pages,""), code: {
      [h,if (page == currentPage): class="currentPage" ; class="page"]
      [h: callback = "CharSheet@"+getMacroLocation()]
      <td class="[r: class]">
        [r: macroLink(page, callback, "none", "Page="+page)]
      </td>
    }]
  </tr>
</table>


Create CharSheetMain on Lib:Test
Code:
[h: propNames = "Strength, Dexterity, Constitution, Intelligence, Wisdom, Charisma"]
<table>
  <tr>
    <td>
      <img src='[r: getTokenImage(100)]'></img>
    </td>
    <td>
      <table id="stats">
        <tr>
          <th>Name</th>
          <th>Score</th>
        </tr>
        [h: class = "oddRow"]
        [foreach(prop, propNames, ""), code: {
          <tr class="[r:class]">
            <td>[r: prop]</td>
            <td>[r: getProperty(prop)]</td>
          </tr>
          [h: class = if(class=="oddRow", "evenRow", "oddRow")]
        }]
      </table>
    </td>
  </tr>
</table>
<hr>
<table>
  <tr>
    <td>
      [h: hpBarArgs = strformat("MaxLen=50; Value=%{HP}; MaxValue=%{MaxHP}; Label=HP")]
      [macro("TrafficLightBar@this"): hpBarArgs]
    </td>
  </tr>
  <tr>
    <td>
      [h: hpBarArgs = strformat("MaxLen=50; Value=%{XP}; MaxValue=%{NextLevelXP}; Label=XP; Color=120,120,255")]
      [macro("StatusBar@this"): hpBarArgs]
    </td>
  </tr>
<table>


Also create CharSheetWeapons on Lib:Test
Code:
[h,macro("GetWeaponNumbers@this"): ""]
[h: wpList = macro.return]
<table>
  [foreach(weapon, wpList, ""), code: {
    [h,macro("GetWeapon@this"): weapon]
    [h: wProp = macro.return]
    <tr class="WeaponName">
      <th>
        [h: name = getStrProp(wProp, "Name")]
        [h: bonus = getStrProp(wProp, "Bonus")]
        [h: damage = getStrProp(wProp, "Damage")]
        [h: callback = "EditWeaponDialog@" + getMacroLocation()]
        [h: args = strformat("Number=%{weapon}; Name=%{name}; Damage=%{damage}; Bonus=%{bonus}")]
        [r: macroLink(name, callback, "none", args)]
      </th>
    </tr>
    <tr>
      <th>Damage</th>
      <td>[r: getStrProp(wProp, "Damage")]</td>
      <th>Bonus</th>
      <td>[r: getStrProp(wProp, "Bonus")]</td>
    </tr>
  }]
</table>


And the last change to make is to CharSheet_css on Lib:Test
Code:
.oddRow { background-color: #FFFFFF }
.evenRow { background-color: #EEEEAA }
#stats th { background-color: #113311; color: #FFFFFF }
.WeaponName a {
    background-color: #55AA55;
    color: white;
    text-align: center;
}
.page a {
   background-color: #5555CC;
   color: white;
}
.currentPage a {
   background-color: #7777FF;
   color: white;
}


So what does this give us? A sihny new frame. Unlike Dialogs, Frames act like
any of the other maptool windows and can be docked on the sides, or with other
windows (forming a tab).

Image

Where it says Main and Weapons on the top, they are links, if you click on
Weapons it will change the CharacerSheet frame to

Image

And as an added bonus, the weapon names are links, if you click on them it
will open up the edit dialog where you can edit them. (note this will
not update the character sheet at this time, but that is left as an
exercise for the reader).

This has just been a short example of what can be done, I am sure people will
come up with some great ideas how to use this.

You can also have dialogs/frames update themselves depending on which tokens
are selected or impersonated (so if you select a new set or impersonate a
different token it can update itself) for the commands you use to do that see
b48 macro addition reference thread for more information.


Last edited by Craig on Wed Dec 03, 2008 4:32 am, edited 1 time in total.

Top
 Profile  
 
User avatar  Offline
Dragon
 
Joined: Thu Sep 11, 2008 1:04 pm
Posts: 923
 Post subject:
PostPosted: Wed Dec 03, 2008 10:00 am 
Nice tutorials. Can't wait to look at them completely when I have more time this weekend. Just wonder but are all the dialog boxes setup to do HTML? I only know some basic HTML but at first glance it looks like HTML coding style.

Also it would be great to have a working example to see and play around with ;). Is there any chance you can upload the campaign file with your tutorial tokens and macros in them?


Top
 Profile  
 
User avatar  Offline
Deity
 
Joined: Tue Jul 01, 2008 6:48 pm
Posts: 6235
 Post subject:
PostPosted: Thu Dec 04, 2008 9:41 am 
Craig, Pyromancer2k mentioned in another thread that these dialogs are private (or can be made to display to only the GM, for instance) - how would that be done (or can it be done)?

It might solve a problem I've been thinking about that came up elsewhere on the forums.


Top
 Profile  
 
 Offline
Great Wyrm
 
Joined: Sun Jun 22, 2008 6:53 pm
Posts: 1961
Location: Melbourne, Australia
 Post subject:
PostPosted: Thu Dec 04, 2008 2:46 pm 
Rumble wrote:
Craig, Pyromancer2k mentioned in another thread that these dialogs are private (or can be made to display to only the GM, for instance) - how would that be done (or can it be done)?

It might solve a problem I've been thinking about that came up elsewhere on the forums.


You can't pop up a dialog on someone else, the reason being the potential issues (just think of all those dialog boxes popping up when players start mucking around aieee). Plus to display a dialog box you need to run a macro I am not sure we want to go down the path of someone else automatically running a macro on your machine.

What you can do is send a link to someone else and clicking on the link runs a macro which displays the dialog. macro links have a tooltip which pops up that lets you verify exactly what macro is going to be run, on which tokens and with which arguments.

*Edit:
I may look at the possibility of allowing trusted macros to do something, but that will have to wait until after I complete some other stuff.


Top
 Profile  
 
User avatar  Offline
Deity
 
Joined: Tue Jul 01, 2008 6:48 pm
Posts: 6235
 Post subject:
PostPosted: Thu Dec 04, 2008 2:56 pm 
Craig wrote:
Rumble wrote:
Craig, Pyromancer2k mentioned in another thread that these dialogs are private (or can be made to display to only the GM, for instance) - how would that be done (or can it be done)?

It might solve a problem I've been thinking about that came up elsewhere on the forums.


You can't pop up a dialog on someone else, the reason being the potential issues (just think of all those dialog boxes popping up when players start mucking around aieee). Plus to display a dialog box you need to run a macro I am not sure we want to go down the path of someone else automatically running a macro on your machine.

What you can do is send a link to someone else and clicking on the link runs a macro which displays the dialog. macro links have a tooltip which pops up that lets you verify exactly what macro is going to be run, on which tokens and with which arguments.

*Edit:
I may look at the possibility of allowing trusted macros to do something, but that will have to wait until after I complete some other stuff.



It's actually less of a big deal than I thought - it was originally in the attempt to develop the "fudging skill rolls" system where the GM has a chance to see a roll before the player does, and fudge it "automatically." I came up with a macro-handoff sequence that worked out.

I don't know how useful it would have been; it was mostly just to see if I could do it.

I would agree that perhaps we don't want to flood each other with dialogs, or allow other people to run anything on each others' machines.


Top
 Profile  
 
 Offline
Great Wyrm
 
Joined: Sun Jun 22, 2008 6:53 pm
Posts: 1961
Location: Melbourne, Australia
 Post subject:
PostPosted: Thu Dec 04, 2008 3:14 pm 
Rumble wrote:
Craig, Pyromancer2k mentioned in another thread that these dialogs are private (or can be made to display to only the GM, for instance) - how would that be done (or can it be done)?

It might solve a problem I've been thinking about that came up elsewhere on the forums.


Campaign


Its not 100% the same as the tutorial as I made some changes to it but its very close.

Also I know it has problems with changing impersonated tokens but its only a short tutorial :)
You could easily fix them by either setting up a macro to be called from the dialog when impersonated token changes, or when the dialog first runs grab the token id and make sure you are always using [token(): ] or switchToken() so you are accessing the correct token. It all depends on if you want the sheet to always refer to same token or always refer to impersonated token. It also wont fail gracefully if there is no token impersonated and you click on the links up the top.


Top
 Profile  
 
User avatar  Offline
Great Wyrm
 
Joined: Fri Mar 28, 2008 11:30 pm
Posts: 1586
Location: Layfayette Hill, PA
 Post subject:
PostPosted: Thu Dec 04, 2008 5:54 pm 
Craig wrote:

....
or when the dialog first runs grab the token id and make sure you are always using [token(): ] or switchToken() so you are accessing the correct token. It all depends on if you want the sheet to always refer to same token or always refer to impersonated token. It also wont fail gracefully if there is no token impersonated and you click on the links up the top.


I have been working on a character sheet and struggling with a couple of points.

1) If I use an abort(0) in a library called macro, a message goes to the chat window stating "Abort() function called."

Calling Campaign Macro:
Code:
[MACRO("CharSheet@Lib:DnD35Pathfinder"): "Main"]
[H: abort(0)]


Library Macro:
Code:
[IF( hasImpersonated() == 0 ), CODE: {
  [dialog("Error"): {
    <html>
      <head>
        <title>Error</title>
      </head>
      <body>
        <br />
         You must <i>impersonate</i> a token to use the character sheet frame.
      </body>
    </html>
  }]
[H: abort(0)]
}]

[frame("CharSheet"): {
  [h: page = getStrProp(macro.args, "Page")]
  [h,if(page==""): page="Main"]
  <html>
    <head>
      <link rel="stylesheet" type="text/css" href="CharSheet_css@[r: getMacroLocation()]">
      <link rel="onChangeImpersonated" type="macro" href="[r: macroLinkText("CharSheet@"+getMacroLocation(), "none", "Page=Main", "impersonated")]">
      <title>[r: token.name]</title>
    </head>
    <body>
      [macro("CharSheetHeader@this"): page]
      <br>
      [macro("CharSheet"+page+"@this"): ""]
    </body>
  </html>
}]


2) I want the character sheet to stay up and autorefresh. I have it partially working IF the token has been impersonated. But if I do not have a token impersonated, the Frame loses focus as to what it is working on. I see from your comments that I should be getting the token.ID and using that ... but I do not see where the Frame has any variable persistence... are you saying I should store the token.ID in a Library property?


Top
 Profile  
 
 Offline
Great Wyrm
 
Joined: Sun Jun 22, 2008 6:53 pm
Posts: 1961
Location: Melbourne, Australia
 Post subject:
PostPosted: Thu Dec 04, 2008 6:46 pm 
lmarkus001 wrote:
I have been working on a character sheet and struggling with a couple of points.

1) If I use an abort(0) in a library called macro, a message goes to the chat window stating "Abort() function called."


Ugh, I will take a look at this me no likey how abort() is implemented...

lmarkus001 wrote:
2) I want the character sheet to stay up and autorefresh. I have it partially working IF the token has been impersonated. But if I do not have a token impersonated, the Frame loses focus as to what it is working on. I see from your comments that I should be getting the token.ID and using that ... but I do not see where the Frame has any variable persistence... are you saying I should store the token.ID in a Library property?


You can do that but if multiple players are running the token you can get into trouble.
If you are wanting to make sure you get the correct token when a link is on the dialog is clicked on you can pass the token id as an argument. (macroLink() allows you to pass arguments).

So when the dialog is run you get the value of say tokenId from macro.args (as a property list) if its not there then you set tokId = currentToken(), otherwise you set tokId to what ever tokenId= in the properties.


Top
 Profile  
 
User avatar  Offline
Giant
 
Joined: Fri Aug 01, 2008 10:38 pm
Posts: 182
Location: Orange County
 Post subject:
PostPosted: Thu Dec 04, 2008 9:17 pm 
Is it at all possible to have a macro run by a player create a frame that only the GM can see? I want to be able to compare attack rolls against defenses, but have the "player x has hit/missed enemy y" appear on a frame that only I can see.


Top
 Profile  
 
User avatar  Offline
Dragon
 
Joined: Thu Sep 11, 2008 1:04 pm
Posts: 923
 Post subject:
PostPosted: Sat Dec 06, 2008 1:19 am 
Since I finished my token updates and Gallery is messed up so I can't post pics to update my Documentation I figured I'd check out all the new stuff.

Anyway I was taking your tutorial and have noticed some errors.

1) The code where you show a person to do their first frame is the same as the Dialog.
2) The Get Weapon Calling Macro has a syntax error. There should he a comma not a colon after the h.
3) For some reason I can't run the edit weapon dialog box. It does the chat fills up and won't run.
4) On the Weapon View Calling Macro you have a comma at the end where there should be a colon.
5) When I try to change to the weapons page I get this error Messages.
Quote:
Invalid condition in IF(isPropertyEmpty("Weapons")) roll option Statement options (if any): h,if(isPropertyEmpty("Weapons")) Statement body: Weapons = "NumWeapons=0;"


I tracked down the 2 macros that use that line and both ran fine on their own. I then tried it on your tutorial campaign and the same thing happen. I did found a weird work around though. If I open char sheet first with the macro. Then click the AddWeapon Macro the chat fills up but doesn't run. Then I click on the Weapons link at the top of the frame it then opens up the list of weapons?? I tried this multiple times and it seems you always have to do that to get it to work. Also I still can't open the Weapon Edit frame when running it from your campaign.


Top
 Profile  
 
 Offline
Great Wyrm
 
Joined: Sun Jun 22, 2008 6:53 pm
Posts: 1961
Location: Melbourne, Australia
 Post subject:
PostPosted: Sat Dec 06, 2008 1:36 am 
PyroMancer2k wrote:
I tracked down the 2 macros that use that line and both ran fine on their own. I then tried it on your tutorial campaign and the same thing happen. I did found a weird work around though. If I open char sheet first with the macro. Then click the AddWeapon Macro the chat fills up but doesn't run. Then I click on the Weapons link at the top of the frame it then opens up the list of weapons?? I tried this multiple times and it seems you always have to do that to get it to work. Also I still can't open the Weapon Edit frame when running it from your campaign.


The chat fills up and doesn't run is a problem with how MapTool handles input text. Depending on how your java is set up and the amount of memory you have allocated and who wrote your JVM you may have enough stack space to avoid the problem or you may not. I already simplified that dialog box to the point where it ran ok on my computer as it was causing that error on my system (the original dialog box had more bling ;) ). It is happening on a lot of macros recently because they are now starting to push towards the point where they complex enough to hit that limit.

I am looking at that problem now and trying to fix it.


Top
 Profile  
 
User avatar  Offline
Dragon
 
Joined: Thu Sep 11, 2008 1:04 pm
Posts: 923
 Post subject:
PostPosted: Sat Dec 06, 2008 3:41 pm 
Craig wrote:
I am looking at that problem now and trying to fix it.


Image


Top
 Profile  
 
Display posts from previous:  Sort by  
Reply to topic  [ 55 posts ]  Go to page 1, 2, 3, 4  Next

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:

Who is online

In total there is 1 user online :: 0 registered, 0 hidden and 1 guest (based on users active over the past 5 minutes)
Most users ever online was 243 on Sun Nov 04, 2012 6:14 am

Users browsing this forum: No registered users and 1 guest





Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group

Style based on Andreas08 by Andreas Viklund

Style by Elizabeth Shulman