Debugging Tutorial
THIS IS AN ADVANCED ARTICLE
Debug Methods For Maptool Scripting
A tutorial to squash little critters from your MT code.
What is this about?
I've been working with MT for over 2 years now and I can still remember the initial struggle I had due to the lack of any debugger. As it turns out there are quite a few methods to debug your code but unfortunately they're not very obvious to find. So here a short summary of available tools.
I've marked this article as 'advanced' as it does assume that you know the basics of MT script, like Library Token, onCampaignLoad and User defined functions.
Pause
The most basic and I think most used method is the 'Pause' method as developed by zeAl. The only way in MT to interrupt the flow of the code is with the use of input(). zeAl created some clever code around input() to use for debugging. His full contribution can be found here: [1]. Its working is simple as shown in this example:
[h:strength = 5] [h:toughness = 10] [h:pause("strength", "toughness")] [r:"This text you'll see AFTER the pause"]
The running code will stop after the toughness=10 line, show the two variables both name and value and after you've clicked ok the code will continue. Its possible to just run
[h: pause()]
in several places in your code so you can check where it crashes. In order for pause to work in your campaign you will need a library token with an onCampaignLoad macro containing the following line:
[ defineFunction("pause", "pause@this", 1, 0 ) ]
and you will also need a macro called 'pause' on the same library token containing the following code:
[ toolkit.DebugVariableCount = argCount() ]
[ toolkit.DebugInputParameter = ".|<html>" +
"<table cellspacing='2' cellpadding='0' style='background-color:#595751'>" +
"<tr><td>" +
"<table width='300px' cellspacing='0' cellpadding='2' style='background-color:#FAF9F5;'>" +
"%{toolkit.DebugVariableRows}</table></td></tr></html>" +
"|Debugger|LABEL|SPAN=TRUE"
]
[ toolkit.DebugVariableRow = "<tr %{toolkit.DebugVariableRowStyle}><td>" +
"<b>%{toolkit.DebugVariableName}</b></td><td>%{toolkit.DebugVariableContent}" +
"</td></tr>"
]
[ toolkit.DebugVariableRows = "<tr style='background-color:#E0DDD5; font-size:1.1em;'><td><b>Variable</b></td><td><b>Value</b></td></tr>" ]
[ count( toolkit.DebugVariableCount ), code:
{
[ toolkit.DebugVariableRowStyle = "" ]
[ toolkit.DebugVariableName = arg( roll.count ) ]
[ toolkit.DebugVariableContent = eval( arg( roll.count ) ) ]
[ if( floor( roll.count/2 ) == roll.count/2 ), code:
{
[ toolkit.DebugVariableRowStyle = "style='background-color:#EDECE8;'" ]
} ]
[ toolkit.DebugVariableRows = toolkit.DebugVariableRows +
strformat( toolkit.DebugVariableRow )
]
} ]
[ if( toolkit.DebugVariableCount == 0 ), code:
{
[ toolkit.DebugVariableRows = "<tr><td style='font-size: 1.4em' align='center'><b>Pause</b></td></tr>" ]
} ]
[ toolkit.DebugBreak = input( strformat( toolkit.DebugInputParameter ) )]
[ abort( toolkit.DebugBreak ) ]
You can also find this code after the above link to zeAl's post. Tip: if you want to copy paste the above code or the code from the post, then FIRST paste it into a simple text editor and copy it from there and THEN paste it into the MT macro. This prevents from unintentional copying e.g. linefeeds (0x0A).
Where pause goes wrong
A couple of useful things to know when you start using pause().
- if you use it at the top of your macro to e.g. check the values of the passed on arguments like this:
[tmp = macro.args] [pause("tmp")] [var1 = arg(0)] [var2 = arg(1)]
then arg(0) will no longer exist!! The value that macro.args contain changes as soon as pause has run as it has its own scope and redefines it. Usually this can lead to inexplicable errors so be ware of this! Its better to use it like this:
[tmp = macro.args] [var1 = arg(0)] [var2 = arg(1)] [pause("tmp")]
- pause can only handle very simple html code, so if you want to debug a dynamic form which you have assigned to a variable I would suggest you use a combination of the Show_HTML method and put a pause() right after that.
The log file
Going to a slightly more advanced method you can start using the log file. First off if MT crashes you can always check the log.txt file which is located in your .maptool directory (varies per OS where that is, for win7 its: C:[username]\.maptool). You will also find a 'logging.xml' file in that directory. The XML file tells maptools what to send to the log.txt file. Per default MT install this will only log generated errors. You can however also replace this file from the one that you can find in the maptool install directory (the one you unzipped initially). In the directory 'Misc' you find a 'macros-logging.xml' file. You can replace the existing XML file in your .maptool directory with that one (don't forget to rename it to logging.xml !) and it will log ALL macro code. This can render into a HUGE log file and slows down MT a bit so be careful with it. In my case I have a PC and Laptop, the laptop I use for running the games, so no logging, the PC I use for coding so logging is always turned on on that PC. If your code crashes or generates weird errors, you can check the log file to see where it went wrong.
The Console
The console is the real kicker, I found out about this after a year or so and since I'm aware of it it has made coding and debugging in MT SO MUCH SIMPLER!!. To activate it you need to do 2 things
- first you need to replace the logging.xml file with the macro-loggin.xml as described here above.
- second you need to edit your mt.cfg file. This file you will find in the install directory. The content will look like something like this:
MAXMEM=1024 MINMEM=64 STACKSIZE=4 JVM=C:\Program Files\Java\jre6\bin\javaw PROMPT=true
depending on your settings and OS. You need to remove only ONE letter: the 'w' from 'javaw'. So it becomes
JVM=[what it reads here differs per OS]java
. . . Download a lib token for this example example2.rptok (token is saved with b73)
Library Token
Introduction to Dialogs and Frames
Introduction to Dialogs and Frames