Poetry In Motion

Making Large & Multilayered Animating Avatars

In this example, we use ALARMEXEC and global functions to build custom animations.

As of the Mac V1.1.3 Palace client, or Windows 1.1.6, you can have self-animating props you select a group of props with their "animate" or "palindrome" (aka "bounce") flags set, and off they go, pretty much lagless and automatic. If animation is what you want, the built-in animation scheme is clearly your first and prefered option 95% of the time.

However....

For these reasons, we still need to fall back on scripting for some prop animation (Prop motion is handled on another page). Here's a simple example, a leftover from the 1996 Valentine's Day Tour d'Iptscrae.

[Missing Illustrations]
Missing here are frames of a flame animation.

The avatar consists of a solid black heart made from two props, surrounded by transparent flame made from four more props. There are only three frames of animation, but that's 12 moving props and two still props fourteen props all told. Even if you could get that many props in the list (Palace only lets you have nine) they wouldn't display correctly, since they overlap and only one could change at a time.
For this custom animation, we use three global variables (and an optional debugging flag called "debugOn," easily removed), and a global function in the ON SIGNON block...

    burnInt	GLOBAL
    burning	GLOBAL
    burnCt	GLOBAL
    200		burnInt	=	; delay in ticks
    FALSE	burning	=	; power switch
    0		burnCt	=	; frame counter

; burn animation loop for hot heart
    burn_it	GLOBAL		; global function....
    {
        burn_it GLOBAL		; declares itself!
        burnInt GLOBAL		; frame rate
        burning GLOBAL		; on/off toggle
        burnCt  GLOBAL		; frame counter
	debugOn GLOBAL
	time	GLOBAL		; alternative for DATETIME
	{
	    {
		"Now Burning @ "
		    time EXEC ITOA &
		    " / " &
		    burnCt ITOA &
		LOGMSG
	    } debugOn IF
	    burnCt 3 % bdx =
	    { [ "hfl1_1" "hfl1_2" "hfl1_3"
		"hfl1_4" "hfl1_5" "hfl1_6"
		"ht_4" "ht_5" ] SETPROPS } bdx 0 == IF
	    { [ "hfl2_1" "hfl2_2" "hfl2_3"
		"hfl2_4" "hfl2_5" "hfl2_6"
		"ht_4" "ht_5" ] SETPROPS } bdx 1 == IF
	    { [ "hfl3_1" "hfl3_2" "hfl3_3"
		"hfl3_4" "hfl3_5" "hfl3_6"
		"ht_4" "ht_5" ] SETPROPS } bdx 2 == IF
	    burnCt ++
	    {
		"Next burn @ "
		time EXEC burnInt + ITOA &
		LOGMSG
	    } debugOn IF
	    burn_it burnInt ALARMEXEC	; reschedule
	} {
	    "Burn Has Stopped at " burnCt ITOA & LOGMSG
	} burning IFELSE
    } burn_it DEF		; end function def

The trick here is to declare burn_it GLOBAL inside the function itself, then have it reschedule itself over and over, using ALARMEXEC each time it runs. It's not really recursion, but it plays recursion on the internet.
We use our three global variables to: turn the animation on and off (burning); keep track of which frame is next (burnCt); and most importantly when using this, to control the speed (burnInt).
It's important to remember that such an animation loop can become a burning lag machine. Unlike built-in animation, it's calling the server for changes at each and every frame change. So it's important that your find an appropriate interval for the animation frames an interval that may need to get changed depending on how many people are around at the time. The default shown here, 200 ticks, is just over 3 seconds between frames. Depending on what sort of tolerances you're willing to put up with, you might be able to push it below 50.
Note too that any other operation that changes the avatar appearance, such as macros, or the ";cost" or BotBot "np" commands, should also set burning to zero (i.e., it should turn the animation off).
Here's some OUTCHAT code to turn this off and on on command. The global function aps is described elsewhere. You can call this by saying "burn" or "burn on" to start animation, and "burn off" to stop it.

; fire costume
    {
	{ 
	    1 burning =
	    0 12 aps EXEC
	    burn_it EXEC
	} {
	    0 burning =
	} "$1" GREPSUB "n" == CHATSTR "burn" == OR IFELSE
	""CHATSTR =
    } CHATSTR "^burn o([nf])" GREPSTR CHATSTR "burn" == OR IF