Under The Hood

The Stuff That Doesn't Show

Welcome to the second part of our biased and opinionated tour of Cyborg scripts. Let's talk for a moment about structure.

I've seen three major schemes for organizing the overall code in users' Cyborg.ipt files:

None!
No imposed scheme at all. Just leave it as it came when you installed The Palace, occasionally inserting bits of ON OUTCHAT code that you might have borrowed or found on the web. A good way to test your friends' cyborgs for this method is to call them a shriner, and watch them pop on the Flying Fez of Shame.
SIGNON The Master
Pile lots of shared code scraps and global variables into the ON SIGNON handler, leaving the OUTCHAT (and also INCHAT) handlers smaller and hopefully faster.
MACRO Master
Instead, pile all of the global definitions into a macro definition, typically ON MACRO0 or ON MACRO1 (This is pretty much the same as the structure above, but makes it easier to reload global definitions; a clever scheme first pointed out by JC). The SIGNON block for such a user usually does nothing but call 0 MACRO
Personally, I use #2, the ON SIGNON method (my SIGNON contains some signon-dependant timers and such). All three methods are valid options. I like to use a lot of global variables and flags and custom functions, so the ON SIGNON block is by far the largest part of my Cyborg file. I use most of those global variables to keep track of the state of my bot. Here's a list of global variables, quoted right from my own hand-built cyborg file. What these are all used for will be explained in subsequent pages....

(Okay, this isn't a complete quotation from the Cyborg.ipt file. Here's why.)
ON SIGNON {
    TICKS itk =
    botHold	GLOBAL
    timeBase	GLOBAL
    debugOn 	GLOBAL
    burning	GLOBAL
    burnInt	GLOBAL
    burnCt	GLOBAL
    facM	GLOBAL
    altM	GLOBAL
    twinPW	GLOBAL
    iptPW	GLOBAL
    iptOn	GLOBAL
    autoPos	GLOBAL
    autoX	GLOBAL
    autoY	GLOBAL

    "\x3bwirf"	iptPW	=	; "\x3b" = semicolon
    "\x3bzoik"	twinPW	=

    0		FALSE	=
    FALSE NOT	TRUE	=

    FALSE	debugOn	=
    DATETIME	timeBase	=
    200		burnInt	=
    FALSE	burning	=
    0		burnCt	=
    FALSE	autoPos	=
    0		autoX	=
    0		autoY	=
    9		facM	=
    8		altM	=
    TRUE	iptOn	=

; end of global variable initializations

That block of GLOBAL declarations is then copied to the INCHAT and OUTCHAT handlers, as well as any Macros etc that might use any of these variables.

The itk variable is NOT global, but something I use to keep track of operations inside of the ON SIGNON block, as we'll see below.
After the variables come the shared global subroutines/functions:

;   ****************************************
;   *** Global Subroutines *****************
;   ****************************************

; return # of seconds since signon
    time	GLOBAL
    {
	timeBase	GLOBAL
	DATETIME timeBase -
    } time DEF

; number of Guests in current room
    count_guests	GLOBAL
    {
	NBRROOMUSERS	r	=
	0		result	=
	0		i	=
	{
	    { result ++ } i ROOMUSER WHONAME "^Guest " GREPSTR IF
	    i ++
	} { i r < } WHILE
	result
    } count_guests DEF

; return true if named user is in current room
; <name> find_name EXEC
;
    find_name	GLOBAL
    {
			seekName	=
	NBRROOMUSERS	r		=
	{
	    0		i		=
	    {
		{
		    1 RETURN
		} i ROOMUSER WHONAME seekName == IF
		i ++
	    } { i r < } WHILE
	} seekName "" == NOT IF
	0
    } find_name DEF

; return position of named user is in current room, or own pos if
;			   not found
; <name> find_pos EXEC
;
    find_pos	GLOBAL
    {
			    seekName	=
	NBRROOMUSERS	r		=
	{
	    0		i		=
	    {
		{
		    i ROOMUSER WHOPOS RETURN
		} i ROOMUSER WHONAME seekName == IF
		i ++
	    } { i r < } WHILE
	} seekName "" == NOT IF
	POSX POSY
    } find_pos DEF

    ;
    ; ...etc.
    ; There are quite a few functions here, then a wrapup:
    ;

    TICKS itk - ITOA " Ticks for SIGNON exec" & LOGMSG
}

which ends the SIGNON block. The itk timer variable lets me know how long the entire SIGNON block took to load, in 1/60th of a second "ticks."
Each OUTCHAT etc handler then needs to have those global functions declared, too, e.g.,

    time	GLOBAL
    time_log	GLOBAL
    find_name	GLOBAL
    count_guests GLOBAL
    bot_say	GLOBAL
    auto_pos	GLOBAL
    leap_to	GLOBAL
    glide_to	GLOBAL
    burn_it	GLOBAL
    aps		GLOBAL
    n_prop	GLOBAL
    costume_set	GLOBAL

My own habit for naming variables and the like is to use multiple words with different separators to name variablesWithCaps and functions_with_underscores. Iptscrae ignores case, so don't make the mistake of thinking that, say, "msX" and "MSX" are different variable names. (Variables and functions used by the BotBot are automatically scoped correctly)