Magsbot Class, Session 4
Saturday March 29, 2003 3pm VRT
note: added remarks or paraphrases are in [brackets], and the order of some chat has been changed for clarity.

Magine: so, everyone read the log from last time?
ZebLith: yep!
Magine: just waiting a few minutes for anne to get here
ZebLith: Okay, I'm finishing off a letter anyways. :)
DLP Anne: hi
Magine: hey :)
DLP Anne: :)
ZebLith: Hi Anne. :)
Magine: brb then we'll start
DLP Anne: k
Magine: ok back
Magine: so, any questions from last time?
DLP Anne: wb  nope
ZebLith: Welcome back, and no questions. :)
Magine: ok...well, to begin with today i wanted to talk about how the bot receives events from the world server
DLP Anne: k
Magine: just so you can have an idea of what the bot is doing internally
Magine: any aw sdk bot will receive messages from the world server only when it calls an sdk function called aw_wait
Magine: so any bot program needs to call aw_wait repeatedly as it runs
Magine: and when the program calls aw_wait, it will be "blocked" until aw_wait is done
        ["blocked" = program will lock up]
Magine: so the program doesn't want to call aw_wait for too long a time.
Magine: when the program calls aw_wait, it specifies how long [it should fetch messages].
Magine: during the call to aw_wait,
Magine: the aw_wait function will itself call functions within the bot program, that are called "handlers"
Magine: when the bot program starts, it calls some other sdk functions that tell the sdk what functions in the bot program should be used to handle each event type
Magine: and that's how aw_wait knows what handler functions to call for each event
DLP Anne: ummm ok lol
ZebLith: Oooh, okay.  (Making sense. ^^)
Magine: take a look now in magsbot, to menu Options/Handlers...
Magine: everyone have that dialog up?
ZebLith: yep
DLP Anne: yeppers
Magine: all of those checkboxes represent a handler within magsbot that responds to messages (events) from the world server
Magine: and each handler within magsbot will send the event message to the behavior table for processing
Magine: you'll notice on the handlers dialog there, that some handlers are for "callbacks"
DLP Anne: the highlighted ones
Magine: yes
DLP Anne: i can read yerppers lol
Magine:  a callback is a message that is sent in response to some function call within the bot program
DLP Anne: sorry im in a funny mood this morning lol
Magine: np, me too :D
Magine: always :D
Magine: callback....for instance, when you create an object in aw,
Magine: you get a "Callback" event, ObjectResult, that tells you the result of the attempt to create the object
ZebLith: oh!
Magine: now the reason for the handlers dialog in magsbot,
Magine: is just so you can turn off handlers that you are sure you're not going to need
Magine: for a particular situation
Magine: so cut down on the number of messages the bot has to process
DLP Anne: oh ok
Magine: although in most cases you probably won't bother doing that....
Magine: i just wanted you to see the list of handlers to give you an idea of what the bot is doing :)
DLP Anne: nope i dont touch little check boxes lol they are there for a reason lol
Magine: :D
ZebLith: it's appreciated, for I will be unchecking several of them... >:D
Magine: i put all of the handlers that magsbot uses on that dialog,
DLP Anne: k
Magine: even though some of them, like login,
Magine: you would probably never uncheck.
ZebLith: yeah, lol
DLP Anne: still its good to know
Magine: yeah
Magine: so, getting back to magsbot specifically (as opposed to aw bots in general)
Magine: (hm, wondering how technical i should get, don't want to confuse things with superfluous information...)
Magine: well anyhow, basically, as magsbot runs, it alternates between calling aw_wait for short periods,
Magine: and processing the event messages that it receives.
Magine: you all have the monitor bar open? ctrl-M
Magine: hello? :D
DLP Anne: i keep it open
ZebLith: lol yes, so do i :)
Magine: ok....well the blue light shows when magsbot is receiving messages,
DLP Anne: sorry Magine lol its hard to be in 2 places at once
Magine: and the yellow light shows when it's processing messages
DLP Anne: k
Magine: the Events bar there shows how many messages have been received but not processed yet.
Magine: as you recall from when we were doing surveys.
DLP Anne: right
ZebLith: heh right :D
Magine: the point of all this, is that you can adjust the amount of time spent receiving messages & processing, respectively
Magine: by using the "synchtimer" command
DLP Anne: k
Magine: just to give you an idea, press f5 and type "synchtimer 1000 50" and click ok
Magine: that's not really a great setting, but just to show you how it works
DLP Anne: hmmm ack new keyboard have to figure out how to get  f5 to work
Magine: you can see that now the blue light stays on for quite a long time each cycle
Magine: your new computer has function keys in a strange place?
DLP Anne: this stupid one has them showing on the side
DLP Anne: not on toip
Magine: sounds ancient :D
ZebLith: ooh, wow
DLP Anne: lol no new
Magine: that's how keyboards used to be on AT's
DLP Anne: they are running across the top but on the side of the keys
Magine: oh i see, the labels are on the sides of the keys
Magine: well, not to get sidetracked.... :D
DLP Anne: go  on lol i will figure that out later
Magine: anyway, as you might notice in magsbot with the timing set to 1000 50,
Magine: while the blue light is on, the program can't respond
Magine: so you want to find a balance,
Magine: between receiving messages quickly enough to prevent lag,
Magine: while not staying in wait state (receiving messages, blue light on) long enough to make the program unresponsive
Magine: now press F5 and type synchtimer 50 500
Magine: that's a more reasonable timing...
Magine: in any case, you won't have to adjust the timing very often, if ever,
Magine: but i wanted to show you that to give you an idea of how the message processing works
DLP Anne: got it working
Magine: everyone with me? :) anyone falling asleep? :D
DLP Anne: nope right here :)
ZebLith: *zzz*  Huh?  ;)  Nope, right here. :)
Magine: ok..... :D
Magine: i should have explained, the two numbers in the synchtimer command:
Magine: the first number is the wait time (how long to receive messages) and the second number is the processing time, both in milliseconds
Magine: so....during the wait phase, magsbot gets messages from the world server, and the handlers send those messages to the behavior table
DLP Anne: ok
Magine: now each message has some data associated with it
Magine: take a look at http://www.activeworlds.com/sdk/
Magine: in particular, scroll down the lefthand frame to the "Events" section
Magine: that shows you all the events that the sdk can send to bots
DLP Anne: cool
Magine: (magsbot [generally] uses the same event names without the AW_ part of the name, btw)
Magine: click on AW_EVENT_CHAT
Magine: you can see there that there are several "attributes" associated with the event
DLP Anne: yeah]
Magine: in this case they are AVATAR_NAME, CHAT_MESSAGE, CHAT_SESSION, CHAT_TYPE
Magine: in magsbot, when an event message is received,
Magine: all the attributes that are associated with that event,
Magine: are send to the behavior table along with the event type ID.
Magine: well, actually,
Magine: events are not sent *directly* to the behavior table,
Magine: because at the rate they are received, they would interrupt and interfere with each other
Magine: since processing a message can easily take longer than the time it takes to receive another message
Magine: so, in magsbot, the events are put into a queue
DLP Anne: i see
Magine: to be processed in the order they were received
Magine: and during the processing phase, a few events are taken from the queue and processed through the behavior table
DLP Anne: so one best not type faster than the bot can process lol
Magine: heheh well there is no problem there, because of the queue
DLP Anne: lol
Magine: unless the bot starts receiving so many events that it can't ever catch up
Magine: in which case you would consider changing the synch timing as we were talking about earlier.
Magine: for instance,
Magine: the default timing in magsbot used to be 1 ms wait, 500 ms processing
Magine: but when running the bot in awrpg,
Magine: i discovered that there was a lot of lag in the response with that timing
Magine: because the events were coming in too slowly
Magine: but when i changed the timing to 50ms wait, 500 ms processing,
Magine: it picked up nicely :)
DLP Anne: cool
ZebLith: ah great!
Magine: anyway, one more point i wanted to make here was,
Magine: that because of the queueing,
Magine: all of the attributes associated with a particular event,
Magine: must be placed in the queue [by magsbot] with the event ID,
Magine: so when the behavior table processes the event,
Magine: it will be able to see the attributes *as they were at the time the event occurred*
DLP Anne: makes sence
Magine: everyone see what i mean?
DLP Anne: yes
Magine: ok....
ZebLith: yeah :)
Magine: so, to see what an attribute is within the [context of  the]behavior table,
Magine: you use the @atr or $atr functions in magsbot
Magine: @atr for a numerical attribute, $atr for a string attribute
Magine: for instance, in the case of the AW_EVENT_CHAT event,
Magine: you could find the name of the speaker by using $atr[AVATAR_NAME]
Magine: or their session number, using @atr[CHAT_SESSION]
Magine: btw, the session number is a unique ID number that gets assigned to every avatar that the bot can see
DLP Anne: ahh ok so that is what those numbers are
Magine: right
Magine: you can use the session number instead of the name for several different functions
Magine: in fact, in the sdk you need to use the session number rather than the name for most things,
Magine: but magsbot can look up the session number automatically for most functions.
Magine: for instance in magsbot you can use the command
Magine: WHISPER  Magine  "Hello there!"
Magine: or
Magine: WHISPER_ 1394 "Hello there!"
Magine: (1394 being my session number at the moment)
DLP Anne: k
Magine: that session number will change each time the bot sees someone, btw...it's not like citizen ID that is constant)
DLP Anne: right
Magine: ok...so to summarize, in magsbot, when an event occurs, the attrbutes are send to the queue with the event ID, then during processing those attributes are available in the behavior table
Magine: if you use the @atr or $atr functions in magsbot to check the value of some attribute that is NOT valid for that particular event,
Magine: then you just get the value directly from the SDK (not the stored value from the queue), which in most cases won't be useful
DLP Anne: oh ok this will take some getting ued to
DLP Anne: used
ZebLith: yeah heh
Magine: i know :) maybe i'm being too technical here....
Magine: or giving you more info that you need at the moment
Magine: but at least you have an idea of how events are processed, hm? :)
DLP Anne: yup :)
ZebLith: yeah! :D
Magine: ok, let's open the behavior table (alt-B) and double-click on the event column
Magine: then click on the Insert Event button
Magine: that shows you a list of all the magsbot events
Magine: a few of them have slightly different names from the SDK web page
Magine: like AW_EVENT_CHAT is called "HEAR" in magsbot
Magine: also, magsbot has a few extra events of its own, that [aren't generated by] the world server
Magine: for instance the STARTUP event, that occurs when the magsbot program is started
DLP Anne: ahh hok i see
Magine: or the CLOCKTICK event [that is generated by a custom timer in magsbot]
Magine: any questions so far?
ZebLith: None here. :)
DLP Anne: nope
Magine: ok...
Magine: well, next i'd like to take a look at the behavior table and go thru how magsbot does some of the standard behaviors,
Magine: so you can see some examples of how to do some more complicated things.
DLP Anne: ok
ZebLith: okay :D
Magine: but first i'm going to go off on a short tangent to explain macros and functions a bit  better :)
DLP Anne: lol ok
Magine: so what you see in the table will make more sense
ZebLith: heh okies :D
Magine: so, you probably all have a basic idea of what functions are, right?
DLP Anne: yes
Magine: a function is like a magic box, you put something into it and get something back out, nevermind where it came from :D
Magine: like the @len function for example
Magine: you put a string into it, and it give you a number, the length of the string, back :D
Magine: and btw here's a chance for me to show you the magsbot pocket calculator :D
Magine: press F3
Magine: you can type any magsbot expression in there and get the result back
Magine: for instance, you can type @len["some string of mine"] in there
Magine: and get back the result = 19 (in the log window)
Magine: anyway, to continue....
DLP Anne: haha I got result=17
Magine: you must have entered a different string than i did :)
DLP Anne: yeah lol ["how do I do this?"]   lol
Magine: there ya go :D
Magine: you can use that window to experiment with functions too, to get a better understanding of how they work
ZebLith: ah great :)
DLP Anne: k
Magine: now, besides built-in functions like @len and a few hundred others
Magine: magsbot also has "macros"
Magine: i originally called these "user-defined functions" but macros is really more accurate
Magine: in general [programming] terms, a macro is like an abbreviation of a longer something, that gets expanded in action
DLP Anne: k
Magine: in magsbot, macros are defined in the userdefs.udf file.
Magine: go to the "." tab of the magsbot action panel, and click "EditUserDefs"
Magine: that's your userdefs.udf file, containing all the macros defined for magsbot.
DLP Anne: oh cool it opens it
DLP Anne: lol
Magine: :)
Magine: there are tons of standard macros that i've put in there, starting where it says "Standard Macros" :D
Magine: and you can of course add your own
Magine: some macros are very very simple, like
Magine: $midiobject="midispk.rwx"
Magine: and some are pretty complicated, like the $title macro you can see there
Magine: (that's not in the standard section but it is in the userdefs.udf that is in the mbot.zip)
Magine: anyway, you don't need to understand all that code yet,
DLP Anne: ok
Magine: as long as you get the idea that a macro is something that gets substituted for something else
Magine: so if you put $midiobject in your code in the behavior table or a button,
Magine: it will get translated to "midispk.rwx"
DLP Anne: ahhh ok
Magine: another example is
Magine: way down in the file is a line that has:
Magine: $avname=$atr[AVATAR_NAME]
Magine: so you can use simply $avname instead of having to type the longer $atr[AVATAR_NAME]
Magine: you could define your own macro like that for any attribute you expect to use often
DLP Anne: i see it so that code is basically letting you shorten it
Magine: right
DLP Anne: kk
Magine: yet another example,
DLP Anne: lol i use eject alot LOL how can it be shortened
Magine: well, eject is a command, not a function
DLP Anne: oh yeah :) lol
Magine: so you can't make a macro out of it
DLP Anne: ahhh ok
Magine: however there is a way you can do that [i.e. abbreviate a sequence of commands into one]....by using the custom buttons. but i don't want to get ahead of myself here :)
DLP Anne: ok
Magine: yet another example of a very frequently used macro is the @eq macro
Magine: you use @eq to compare strings, it returns "true" (1) if the strings match
Magine: like
Magine: @eq[$avname,Magine]
Magine: well, @eq is actually a macro for
Magine: (@icmp[~1,~2]=0)
Magine: @icmp is a built-in function that also compares strings
DLP Anne: blank stare lol
Magine: @icmp is a built-in function that compares strings alphabetically
DLP Anne: ok
Magine: it returns 0 if the strings match,
Magine: a negative number if the first string comes before the second string, alphabetically
Magine: or a positive number if the second string comes before the first, alphabetically
Magine: try it, using F3
Magine: type something like
Magine: @icmp["first string","second string"]
Magine: that will give you -1 because "first string" comes before "second string" alphabetically
DLP Anne: i got result=1
ZebLith: ditto :)
Magine: what strings did you enter?
ZebLith: @icmp["Mankey","Magine"]
DLP Anne: @icmp["this is neat","how is this done?"]
Magine: if you got a 1, it's because the second string comes first, alphabetically
DLP Anne: ahah
ZebLith: right.  perfect :D
DLP Anne: mag comes before man
Magine: always :P
DLP Anne: gotcha
Magine: lol
ZebLith: lol
DLP Anne: that sounded funny lol
Magine: there is also a @cmp function that does that same thing, but it's case-sensitve
Magine: you all know what that means, right?
ZebLith: anywho ^^ yeah.  so, it returns the same kind of results, -1 0 1?
Magine: yes
DLP Anne: k
Magine: so, the macro @eq is derived from the built-in @icmp function
Magine: somewhere in the userdefs.udf file is this line:
Magine: @eq[$,$]=(@icmp[~1,~2]=0)
Magine: what that means is,
Magine: "when you see @eq with two strings as parameters, then substitute this expression using @icmp with the parameters inserted where the ~1 and ~2 are".
Magine: the $,$ tells magsbot that the @eq requires two string parameters (or "arguments" in programmerese)
Magine: and the ~1 and ~2 in the translation shows where the arguments get plugged in.
DLP Anne: k
Magine: let's take a short break
DLP Anne: ok thank you :)
DLP Anne: brb
Magine: but does that makes sense so far?
ZebLith: yeah.  :)  I'm curious though...
ZebLith: okay, so if I put in @eq["Right","Wrong"] and @icmp["Right","Wrong"]  I should get the same result in theory?
Magine: no...[because] if you look carefully, the macro isn't just @eq[$,$]=@icmp[~1,~2]
Magine: it's @eq[$,$]=(@icmp[~1,~2]=0)
Magine: you would get the same thing as @eq["Right","Wrong"] if you put
Magine: (@icmp["Right","Wrong"]=0)
ZebLith: oh, right!
ZebLith: forgot that wonderful =0
Magine: yep
DLP Anne: back  thanks magine :)
Magine: np anne :)
ZebLith: okay, that makes sense. welcome back anne!
DLP Anne: ty Zeb :)
Magine: what the =0 does, zeb, is to compare the result of the @icmp with 0
Magine: if @icmp returns 0 (meaning that the strings match) then @icmp=0 will be true and the @eq macro will return 1
Magine: you see how that works?
ZebLith: yes :D
Magine: anne?
DLP Anne: yes
DLP Anne: im with you
Magine: ok
DLP Anne: so far anyway
Magine: ok, well time is almost up, so i won't try to get into the behavior table examples this time (unless everyone wants to stay longer, but i will need a break myself if so)
Magine: but in the time left, we could try to define our own macro to show you how it works
DLP Anne: I cant stay longer son wants attention lol
Magine: ok
Magine: so let's just take the remaining 10 minutes or so to try a macro definition :)
DLP Anne: i get to go outside and play with supersoaker water guns lol
[Magine: kind of cold for that, isn't it? :D]
DLP Anne: okies
Magine: hmm, let me see...
Magine: ok, this will be pretty useless, but it will give you an idea anyway :D
DLP Anne: ok
ZebLith: lol okies :)
Magine: assuming you all still have userdefs.udf open in notepad?
DLP Anne: yup
ZebLith: yes
Magine: ok, pick a line in there and put...let me see.......
Magine: @foo[$,$]=$cat[~2,~1]           [<<< this is a goof! read on...]
DLP Anne: you mean under macros?
Magine: anywhere in the userdefs file, on a  line by itself (but better to put it in the custom section above the "Standard Macros" line)
Magine: that is, it will work anywhere, but better to leave the standard section alone
Magine: just for the sake of orderliness :D
DLP Anne: ok done
Magine: then save file (File/Save, but you dont need to close the file)
Magine: and then in magsbot, press Ctrl-F11 or menu File/Open Macros
Magine: everyone done that?
ZebLith: yes :)
Magine: before we test it,
DLP Anne: yup
Magine: i'll explain that the $cat function, which is a built-in function,
Magine: just sticks two strings together into one
Magine: like $cat["one","two"] would return "onetwo"
Magine: so knowing that, what do you think our new macro will do?
ZebLith: it will combine the two strings we enter into a single line.
Magine: (hm, well actually guess what...i goofed!)
DLP Anne: lol
ZebLith: oops ^^
Magine: because that should have been $foo not @foo
Magine: @foo would be for a function that returns a number, not a string
Magine: what version of magsbot are you all running?
DLP Anne: the latest
ZebLith: 4.0 as requested to be used
DLP Anne: same
Magine: ok, well then i won't have you try the bogus function to see what happens :D
Magine: if you were using 4.1 b8 then it would just give you an error message in the log window
DLP Anne: lol i changed it already
ZebLith: lol *watches older mags version explode*
Magine: but 4.0 i think would cause [an exception with a] pop-up error message
DLP Anne: no i got one in the window
Magine: ok
DLP Anne: acess violation
Magine: yeah
Magine: well let's change it in the userdefs to $foo= etc.
Magine: and save it again
DLP Anne: already done
Magine: and Ctrl-F11 load it again
DLP Anne: i hit control f11 and a window comes up to load the userdefs?
Magine: anne, yes
DLP Anne: kk when i try to load I get an error or am i not supposed to
Magine: uhh, hmm, no not supposed to [get an error when loading]
Magine: what is the error?
DLP Anne: i never closed it once I saved it the first itme
Magine: doesn't matter if you close it as long as you save it
Magine: what error message?
DLP Anne: acess violation at address 004729B4
Magine: anne, if you're sure you typed the macro right anne, then just restart magsbot
DLP Anne: ok
Magine: sometimes if there is an error in a macro when it loads, it will mess things up
Magine: because if there's an error it will stop loading, and if there are macros missing then many things in the standard behavior table will crash
DLP Anne: LOL it wont let me x out
Magine: ah right
Magine: well here is what you can do with that situation :D
Magine: (maybe i need to change this, but magsbot won't quit if it has an error while trying to quit)
Magine: you can force it to quit by making it ignore errors while quitting
Magine: press F5 and type
Magine: trap { quit }
Magine: and click Ok
Magine: the trap command turns off error messages
DLP Anne: kk
Magine: did that do it?
DLP Anne: yup and she is back
Magine: ok, so any other guesses as to what [our new macro] will do?
Magine: this is a trick question, look carefully :)
ZebLith: Oh!  I have another guess of what it will do... concerning order. ;)
Magine: zeb, i think you have it :)
ZebLith: second string first, first last.  correct?
Magine: (to ZebLith) yes
Magine: ok, so with out $foo macro, as zeblith has figured out,
Magine: it will combine the two strings, but in reverse order
DLP Anne: ahhh ok
Magine: because in the macro the order of the arguments is ~2,~1
ZebLith: Can you add more, like change the code to $foo[$,$,$,$]=$cat[~1,~3,~2,~4]?
Magine: zeb, yes indeed :) up to 12 arguments are possible
Magine: and arguments can also be numeric if you want
Magine: so you could have
Magine: @foo[@,@,@]=~1+~2*~3
Magine: for example.
ZebLith: ah!  I see.  okies :)
Magine: and you can mix them of course, numeric and string
Magine: the only thing is, the result has to match the macro type
DLP Anne: this is all programming right
Magine: yep :)
DLP Anne: ahhh ok
DLP Anne: i will leave the programming to you lol but its good to know
Magine: lol
Magine: well putting stuff in the behavior table is programming too :)
DLP Anne: k
Magine: and creating your own buttons is also
DLP Anne: i will learn  may take longer than zeb  lol but i will try
Magine: just play with it, a little at a time, you'll get it :)
ZebLith: You'll do great Anne. :)
DLP Anne: ty :)
Magine: so next time we will take a look at some of the behavior table code and i will explain why it does what it does :)
DLP Anne: ok
Magine: ok folks, see you all next time i hope :)
DLP Anne: will be there :)
DLP Anne: here too
Magine: any last questions?
ZebLith: lol :)  I'll remember to set my alarm again. ;)
Magine: zeb, ok good :)
DLP Anne: magine so is mine LOL
ZebLith: nuuuu! :D  okies, well no questions here.  but next time probably. ;)
Magine: 'k
DLP Anne: same here no questions :)
Magine: bye bye then, see ya's next time :)
ZebLith: Bye Magine! :)
DLP Anne: byeeeeee to you both :)