It's a Bird, It's a Plane, It's....

Gliding Around on the Screen

Now with BotBot Support! (see "leap")

Cyborg functions can help you around the screen space of Palace rooms in two key ways:

  1. Moving to a location via script lets you easily move to "door" areas without "falling in."
  2. Animated movements can be lots of fun.
For the first, I use a simple bit of OUTCHAT called "mpos," sort of a cousin to the universal "msay:"

; jump to mouse pos
    {
        MOUSEPOS SETPOS
        ""    CHATSTR    =
    } CHATSTR "mpos" == IF

just point the mouse where you want to go, and type "mpos" and the <RETURN> key.
Animating your avatar around on the screen requires a bit more work, but it can pay off with the occasional ego-boosting "kewl!" comment. Here are two animated movements, "glide" and "leap." Both are defined in the ON SIGNON block as global procedures, and both share an additional dedicated function that selects a motion-blurred avatar based on the current direction. First, let's start with the avatar switcher.

;select the correct prop based on direction -- called as
; <xMotion> <yMotion> moving_prop EXEC
;
    moving_prop    GLOBAL
    {
            deltaY    =
            deltaX    =
        {
            {
                [ "NoBlur" ] SETPROPS
            } {
                [ "NSblur" ] SETPROPS
            } deltaY -4 > deltaY 4 < AND IFELSE
        } {
            {
                { [ "NoBlur" ] SETPROPS }
                { [ "EWblur" ] SETPROPS }
                deltaX -4 > deltaX 4 < AND IFELSE
            } {
                deltaY 100 * deltaX / t100    =
                { -1 t100 *= } t100 0 < IF
                {
                    {
                        [ "NSblur" ] SETPROPS
                    } {
                        {
                            [ "EWblur" ] SETPROPS
                        } {
                            [ "NWblur" ] SETPROPS
                        } t100 41 < IFELSE
                    } t100 240 > IFELSE
                } {
                    {
                        [ "NSblur" ] SETPROPS
                    } {
                        {
                            [ "EWblur" ] SETPROPS
                        } {
                            [ "NEblur" ] SETPROPS
                        } t100 41 < IFELSE
                    } t100 240 > IFELSE
                } deltaX 0 < deltaY 0 < AND
                  deltaX 0 > deltaY 0 > AND OR IFELSE
            } deltaY 0 == IFELSE
        } deltaX 0 == IFELSE
    } moving_prop DEF

[Missing Illustration]
Missing here is a killer illustration showing a prop and its various motion states. Really.

Of course, this means that you need the appropriate props, and they'd better have different names than the ones indicated here, or you'll soon find that you're having all sorts of prop-name collisions with everyone else who's also copied the same code and made their own props with the same names.

Clever readers might point out that this big cascade of IFs could be simplified by the use of GLOBAL arrays for the collection of props. They'd be right. Only one problem with that idea: global arrays don't work in the current version.
Using the above procedure to change props, we can now glide around the palace in style, using the following function:

; <x> <y> glide_to EXEC
;   glides from the current position to a new one,
;    using motion-blurred props
    glide_to    GLOBAL
    {
        dstX    GLOBAL
        dstY    GLOBAL
        srcX    GLOBAL
        srcY    GLOBAL
        prvX    GLOBAL
        prvY    GLOBAL
        nSteps  GLOBAL
        Stepper GLOBAL
        altM    GLOBAL
        facM    GLOBAL
                    dstY    =
                    dstX    =
        POSX            srcX    =
        POSY            srcY    =
        srcX srcY SETPOS
        dstX srcX -        dx    = 
        dstY srcY -        dy    = 
        dx 22 /            nSteps    =
        { -1 nSteps *= }    0  nSteps > IF
        { 12 nSteps  = }    nSteps 12 > IF
        {  4 nSteps  = }    nSteps  4 < IF
        0        Stepper    =
        0        ctr    =
        30        arcdel    =
        srcX        prvX    =
        srcY        prvY    =
        altM MACRO
        {
            {
                srcX        GLOBAL
                srcY        GLOBAL
                dstX        GLOBAL
                dstY        GLOBAL
                prvX        GLOBAL
                prvY        GLOBAL
                nSteps      GLOBAL
                Stepper     GLOBAL
                moving_prop    GLOBAL
                dstX srcX - Stepper * nSteps 1 - / srcX + nx =
                dstY srcY - Stepper * nSteps 1 - / srcY + ny =
                nx prvX -     dx =
                ny prvY -     dy =
                nx ny SETPOS
                dx dy moving_prop EXEC
                nx            prvX =
                ny            prvY =
                Stepper ++
            } arcdel ALARMEXEC
            30 arcdel +=
            ctr ++
        } { ctr nSteps < } WHILE
        {
            dstX    GLOBAL
            dstY    GLOBAL
            dstX dstY SETPOS
        } arcdel ALARMEXEC
        { facM GLOBAL facM MACRO } arcdel 15 + ALARMEXEC
    } glide_to DEF

If we don't want to alter our props as we go, the whole thing can be simplified somewhat by removing the MACRO and moving_prop calls...

; <x> <y> glide_to_plain EXEC
;   glides from the current position to a new one, NO PROP CHANGES
    glide_to_plain    GLOBAL
    {
        dstX    GLOBAL
        dstY    GLOBAL
        srcX    GLOBAL
        srcY    GLOBAL
        prvX    GLOBAL
        prvY    GLOBAL
        nSteps  GLOBAL
        Stepper GLOBAL
                    dstY    =
                    dstX    =
        POSX            srcX    =
        POSY            srcY    =
        srcX srcY SETPOS
        dstX srcX -        dx    = 
        dstY srcY -        dy    = 
        dx 22 /            nSteps    =
        { -1 nSteps *= }    0  nSteps > IF
        { 12 nSteps  = }    nSteps 12 > IF
        {  4 nSteps  = }    nSteps  4 < IF
        0        Stepper =
        0        ctr     =
        30       arcdel  =
        srcX     prvX    =
        srcY     prvY    =
        {
            {
                srcX        GLOBAL
                srcY        GLOBAL
                dstX        GLOBAL
                dstY        GLOBAL
                prvX        GLOBAL
                prvY        GLOBAL
                nSteps      GLOBAL
                Stepper     GLOBAL
                dstX srcX - Stepper * nSteps 1 - / srcX + nx =
                dstY srcY - Stepper * nSteps 1 - / srcY + ny =
                nx ny SETPOS
                nx            prvX =
                ny            prvY =
                Stepper ++
            } arcdel ALARMEXEC
            30 arcdel +=
            ctr ++
        } { ctr nSteps < } WHILE
        {
            dstX    GLOBAL
            dstY    GLOBAL
            dstX dstY SETPOS
        } arcdel ALARMEXEC
    } glide_to_plain DEF

Okay, let's get down to looking at what the heck is going on in here. Both versions have the same structure: a launch preamble, a loop of scheduled position (and and possible propchange) events, and a final positioning at the desired location.
I always use ALARMEXEC to schedule animated events. Many of the animation scripts that have surfaced in discussion groups and on the web use a simpler approach: "pile it all on as fast as you can immediately." This results in a smaller, simpler script; it also results in significant lag and less-predictable results. By delaying events (here each loop gets a 30-tick delay, or about 1/2 second), the function executes faster (it's just scheduling the events, not actually executing them); time is allowed for the other users to see what's happening; and we're leaving lots of time in between events (500 milliseconds is a lot for most computers) to avoid locking-up the display with lag.
If you're quick, you can even enter text and talk while gliding.
The expense of this route: the function is larger, and a lot of GLOBAL variables are used and redundantly declared. These are real costs, but minor ones.
The last post-loop positioning call is needed because Iptscrae only understands integers, not floating-point numbers a purely incremental approach might not guarantee that we've really hit the mark we were aiming for.
Press here to see yet another alternative version of this function.
The "glide" functions drag you across the screen in an evenly-tempered line. We can change the math in the center of the loop to make alternative paths. The following "leap" function makes a clean parabolic path, and even tunes itself to make sure it fits on the screen....

; <x> <y> leap_to EXEC
    leap_to    GLOBAL
    {
        dstX    GLOBAL
        dstY    GLOBAL
        srcX    GLOBAL
        srcY    GLOBAL
        prvX    GLOBAL
        prvY    GLOBAL
        nSteps  GLOBAL
        Stepper GLOBAL
        toss    GLOBAL
        facM    GLOBAL
        altM    GLOBAL
                    dstY    =
                    dstX    =
        POSX        srcX    =
        POSY        srcY    =
        srcX srcY SETPOS
        dstX srcX -   dx    = 
        dstY srcY -   dy    = 
        dx dy + 11 /        nSteps    =
        { -1 nSteps *= }  0  nSteps > IF
        { 12 nSteps  = }  nSteps 12 > IF
        {  4 nSteps  = }  nSteps  4 < IF
        srcY dstY + 2 /    toss    = 
        { 164    toss    = }          toss 164 > IF
        3 toss *=
        0        Stepper =
        0        ctr     =
        30       arcdel  =
        srcX     prvX    =
        srcY     prvY    =
        altM MACRO
        {
            {
                srcX    GLOBAL
                srcY    GLOBAL
                dstX    GLOBAL
                dstY    GLOBAL
                prvX    GLOBAL
                prvY    GLOBAL
                nSteps  GLOBAL
                Stepper GLOBAL
                toss    GLOBAL
                moving_prop    GLOBAL
                dstX srcX - Stepper * nSteps 1 - / srcX +        nx    =
                dstY srcY - Stepper * nSteps 1 - / srcY +
                    toss toss Stepper * nSteps 1 - / -
                    Stepper * nSteps 1 - / -                     ny    =
                nx prvX -                                        dx    =
                ny prvY -                                        dy    =
                nx ny SETPOS
                dx dy moving_prop EXEC
                nx    prvX    =
                ny    prvY    =
                Stepper ++
            } arcdel ALARMEXEC
            30 arcdel +=
            ctr ++
        } { ctr nSteps < } WHILE
        {
            dstX        GLOBAL
            dstY        GLOBAL
            altM        GLOBAL
            dstX dstY SETPOS
            altM MACRO
        } arcdel ALARMEXEC
        { facM GLOBAL facM MACRO } arcdel 15 + ALARMEXEC
    } leap_to DEF

We leave it as an exercise to come up with a leap_to_plain version.
As functions, these can be used in any part of your script that might need to move the avatar around. Think of them as fancy replacements for the built-in SETPOS command. The simplest user interface is to just call them directly in the OUTCHAT block. Just point the mouse to your desired destination and type "glide" or "leap."

    leap_to	GLOBAL
    glide_to	GLOBAL

; straight line
    {
	MOUSEPOS glide_to EXEC
	"" CHATSTR =
    } CHATSTR "glide" == IF

; arcing leap
    {
	MOUSEPOS leap_to EXEC
	"" CHATSTR =
    } CHATSTR "leap" == IF