It's a Bird, It's a Plane, It's....Gliding Around on the ScreenNow with BotBot Support! (see "leap") |
Cyborg functions can help you around the screen space of Palace rooms in two key ways:
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 |
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 |