Syntactic errors are illegal statements, faulty constructions, typos. Logic errors occur when your code is not doing what you expect it to do, even when all the statements are doing their job properly.
The xelagots do not have a proper debugging tool, although some syntactic errors are detected by the scripting engine. As from x1 version 2.9999950 and Av99Bot/SrvcXlgBot version 1.66, some severe syntactic errors will cause the script to stop running. The x1 xelagot will, in these cases, print an error message on its chat screen, stating the reason. The severe syntactic errors are detected either when the script initialises, or at runtime.
Initialisation errors:
Runtime errors:
There are a few other mixed syntactic/logic errors which, although they may or may not stop the execution, are also shown on the chat screen: LABEL not found (applies to labels, subs, texts, gives error message and OnLabelNotFound event.), RUN file not found...
Up to version 2.9999950/1.66, some of these errors could cause the program to freeze (excessively long loops in event handlers and in SUSPEND... DO blocks) or cause a stack overflow (recursion and circular reference). It is still possible to have a loop without exit, but this will only affect the correct execution of the script, not the application (it is a logic error).
Label, Sub or Event not found. This is an error. Goto French requires, somewhere in the same section a Label French. Gosub English expects a sub called Sub English, and OnChatEvent Chat expects an event handler called Event Chat. If the Label, Sub or Event are not found, an error message is printed and an event is triggered: LabelNotFound, but the script does not abort (because the strings French, English and Chat could be packed in a string variable: Goto $F, Gosub $E, OnChatEvent $C).
What about typos and undeclared variables? The best way to track these is to test your script step by step. Add some SayConcat or SecretConcat statements (which you'll remove or comment out once the tests are done) at crucial points of the script: these can be used to show the value of variables, test if an Event handler is working, etc.
My script used to work fine, now it stops with an error message or does not work properly :( Initialisation errors are easy to solve, just check that you don't miss the corresponding xxEnd statements. Runtime errors are more difficult to solve. If the script stops running, check the error message in the chat screen: it will show you the number of the line where the error occurred (line numbers start at 1 after the line that says [Script]), and the nature of the error. The most common error is a GOTO out of scope (which gives an error message on screen and OnLabelNotFound event but does not stop the script), for example:
Sub One ... some code GoTo OneOut EndSub Label OneOut ... some code EndSub Sub Two ... some code Goto OneOut EndSub |
The first Goto OneOut, in Sub One, is perfectly correct,
because Label OneOut is within the scope of Sub One (the last
EndSub before Sub Two closes Sub One).
The second Goto OneOut, in Sub Two, is illegal: Label OneOut is not in Sub Two. |
The solution to the previous example is actually quite simple:
Sub One ... some code GoTo OneOut EndSub Label OneOut ... some code EndSub Sub Two ... some code Goto TwoOut EndSub Label TwoOut ... similar code ... as after OneOut EndSub |
If you solve this doing a copy-paste, you must re-name any Labels in the new section so that they are not duplicated!
If you wish your script to stop on all errors it traps, while debugging, install the two error event handlers and put an End statement in them:
OnErrorEvent Error OnLabelNotFoundEvent Error ... Event Error Say Aborting script! End EndEvent |
Examples of loops, in blue the good ones, in red the faulty ones:
.. [Script] .. some code OnChatEvent Chat Label MainLoop Goto MainLoop .. more code End Event Chat ... Gosub Process ... EndEvent Sub Process Label ProcessLoop Goto ProcessLoop EndSub |
Goto MainLoop is fine (and necessary if you need to wait for
events to happen): it is in the main part of the script, and the
Goto statement returns control to the application (as well as
setting the script pointer to Label MainLoop).
Goto ProcessLoop is fatal: it is in an event handler (because it is called from an event handler), and would cause the bot application to freeze and eventually crash. |
How to use Suspend correctly, a partial example from an Avatars2000 script. This bit of code is in a Sub called from the main section of the script, and uses Suspend... Do to speed up the action in the loop. All variables were declared and initialised at the begining of the script, the bot is surveying the zone in question. It filters some objects from the survey to the Res buffer, and then, in a loop, recovers them one by one from this buffer and deletes them in the world.
ResClear FilterClear Concat $m $GZTop "," $GZUpDoor "," $GZUpWall FilterModel $m ResFromSurveyFilter ResCount %r %i = 1 Label GZOff_Top IfInt %i > %r Goto GZOff_TopOut Mod %k %i 15 IfInt %k = 0 Do Suspend IfGetResObjectItem ~a %i # ObjectDeleteED ~a Inc %i Goto GZOff_Top Label GZOff_TopOut Do Wait 10 |
I could have used the code in the next example, without a Suspend.. Do construction, but it would have been very slow, sending one object per heartbeat, because any Goto in the Main part of the script (not in an event handler) or in a Sub called from Main returns control to the application before resuming the script execution:
ResClear FilterClear Concat $m $GZTop "," $GZUpDoor "," $GZUpWall FilterModel $m ResFromSurveyFilter ResCount %r %i = 1 Label GZOff_Top IfInt %i > %r Goto GZOff_TopOut IfGetResObjectItem ~a %i # ObjectDeleteED ~a Inc %i Goto GZOff_Top Label GZOff_TopOut Wait 10 |
If you need to do lengthy operations as a result of an event, you must do that outside the event handler. Here is how you could tackle this (schematically):
... in the main part var &Person OnChatEvent Chat Label MainLoop Goto MainLoop Label HaHa # lengthy processing # for Chat event happens here ... some code here # then restore chat processing OnChatEvent Chat # and go back to the loop Goto MainLoop End Event Chat GetChatPerson &p GetChatline $a ... take a decision here IfString "ha ha" IsIn $a Gosub PrepareHaHa EndEvent Sub PrepareHaha # stop event processing OnChatEvent # save the chat person # if you need to use it &Person = &p # set the pointer # to Label HaHa # in the main part ResetTo HaHa EndSub |