backIndex

Xelagot action script

Errors and debugging

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
Using the Mod operator, the script returns control to the application every 15 objects with a Do statement, and uses Suspend to send another 15 objects without returning control to the application (Suspend does not allow the script to return control to the application until a Do is issued). After the end of the loop, Do makes sure control is passed back to the application. If I had not used the Mod operator to regulate the Suspend...Do loop, the program might have crashed (and before that, the bot might have been disconnected from the world for sending too many objects to be deleted).

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



backIndex