Second Life Copybot
ZHAO-II-core MGJEmod 1.1.9 - Printable Version

+- Second Life Copybot (https://secondlifecopybot.com)
+-- Forum: SECOND LIFE PRODUCTS (https://secondlifecopybot.com/forum-1.html)
+--- Forum: SCRIPTS (https://secondlifecopybot.com/forum-1022.html)
+---- Forum: SCRIPTS (https://secondlifecopybot.com/forum-8.html)
+----- Forum: Avatar Augmentation Scripts (https://secondlifecopybot.com/forum-51.html)
+----- Thread: ZHAO-II-core MGJEmod 1.1.9 (/thread-738.html)



ZHAO-II-core MGJEmod 1.1.9 - boogaloo - 02-18-2013

PHP Code:
/*
Ziggy, Bornslippy Ruby presents...
ZHAO-II-core MGJEmod 1.1.9
Tags: animations, attachments, avatar, chat, collision, controls, communications, dialog, ground, inventory, math, link, owner, permissions, physics, primitive, region, scripts, teleport, time, timer, vehicle, world, featured
Description: 
License:
None
http://secondlife.coolminds.org
*/

// ZHAO-II-core - Ziggy Puff, 07/07

/////////////////////////////////////////////////////////////////////////////////////////////////////
// Main engine script - receives link messages from any interface script. Handles the core AO work
//
// Interface definition: The following link_message commands are handled by this script. All of 
// these are sent in the string field. All other fields are ignored
//
// ZHAO_RESET                          Reset script
// ZHAO_LOAD|<notecardName>            Load specified notecard
// ZHAO_NEXTSTAND                      Switch to next stand
// ZHAO_STANDTIME|<time>               Time between stands. Specified in seconds, expects an integer.
//                                     0 turns it off
// ZHAO_AOON                           AO On
// ZHAO_AOOFF                          AO Off
// ZHAO_SITON                          Sit On
// ZHAO_SITOFF                         Sit Off
// ZHAO_RANDOMSTANDS                   Stands cycle randomly
// ZHAO_SEQUENTIALSTANDS               Stands cycle sequentially
// ZHAO_SETTINGS                       Prints status
// ZHAO_SITS                           Select a sit
// ZHAO_GROUNDSITS                     Select a ground sit
// ZHAO_WALKS                          Select a walk
//
// ZHAO_SITANYWHERE_ON                 Sit Anywhere mod On 
// ZHAO_SITANYWHERE_OFF                Sit Anywhere mod Off 
//
// ZHAO_TYPE_ON                        Typing AO On 
// ZHAO_TYPE_OFF                       Typing AO Off 
//
// ZHAO_TYPEKILL_ON                    Typing Killer On 
// ZHAO_TYPEKILL_OFF                   Typing Killer Off 
//
// So, to send a command to the ZHAO-II engine, send a linked message:
//
//   llMessageLinked(LINK_SET, 0, "ZHAO_AOON", NULL_KEY);
//
// This script uses a listener on channel -91234. If other scripts are added to the ZHAO, make sure 
// they don't use the same channel
/////////////////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////////////////
// New notecard format
//
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Lines starting with a / are treated as comments and ignored. Blank lines are ignored. Valid lines 
// look like this:
//
// [ Walking ]SexyWalk1|SexyWalk2|SexyWalk3
//
// The token (in this case, [ Walking ]) identifies the animation to be overridden. The rest is a 
// list of animations, separated by the '|' (pipe) character. You can specify multiple animations 
// for Stands, Walks, Sits, and GroundSits. Multiple animations on any other line will be ignored. 
// You can have up to 12 animations each for Walks, Sits and GroundSits. There is no hard limit 
// on the number of stands, but adding too many stands will make the script run out of memory and 
// crash, so be careful. You can repeat tokens, so you can split the Stands up across multiple lines. 
// Use the [ Standing ] token in each line, and the script will add the animation lists together.
//
// Advanced: Each 'animation name' can be a comma-separated list of animations, which will be played 
// together. For example:
//
// [ Walking ]SexyWalk1UpperBody,SexyWalk1LowerBody|SexyWalk2|SexyWalk3
//
// Note the ',' between SexyWalk1UpperBody and SexyWalk1LowerBody - this tells ZHAO-II to treat these 
// as a single 'animation' and play them together. The '|' between this 'animation' and SexyWalk2 tells 
// ZHAO-II to treat SexyWalk2 and SexyWalk3 as separate walk animations. You can use this to layer 
// animations on top of each other.
//
// Do not add any spaces around animation names!!!
//
// The token can be one of the following:
//
// [ Standing ]
// [ Walking ]
// [ Sitting ]
// [ Sitting On Ground ]
// [ Crouching ]
// [ Crouch Walking ]
// [ Landing ]
// [ Standing Up ]
// [ Falling ]
// [ Flying Down ]
// [ Flying Up ]
// [ Flying ]
// [ Flying Slow ]
// [ Hovering ]
// [ Jumping ]
// [ Pre Jumping ]
// [ Running ]
// [ Turning Right ]
// [ Turning Left ]
// [ Floating ]
// [ Swimming Forward ]
// [ Swimming Up ]
// [ Swimming Down ]
//
/////////////////////////////////////////////////////////////////////////////////////////////////////

// Johann Ehrler, 04/19/2008:
//          Added support for custom animation timing.
//
// Johann Ehrler, 04/06/2008:
//          Some optimations are done...like cleaning up the code and merge it with newly
//          developed functions from a trunk of the core script.
//          Added the byte count to the free memory display for a much better geek factor. ;o)
//          The channel for the listener depends now on the owner UUID...not really necessary but funny.
//          Corrected some typos, redundant whitespaces and indentation.
//          Set Marcus change date to the right year. ;P

// Marcus Gray, 03/26/2008:
//          Included Seamless Sit mod by Moeka Kohime (core script).
//          Freed some memory DELETING THE DEFAULT UNOVERRIDABLE ANIMS!!!!!!!! (core script)
//          Added sit anywhere functionality to replace stands by groundsits (core script).
//          Therefore changed functionality of Sit-ON/OFF button to work as Sit Anywhere button (interface).

// Ziggy, 07/16/07 - Warning instead of error on 'no animation in inventory', that way SL's built-in
//                   anims can be used 
//
// Ziggy, 07/14/07 - 2 bug fixes. Listens aren't being reset on owner change, and a typo in the 
//                   ground sit animation code
//
// Ziggy, 06/07:
//          Reduce script count, since idle scripts take up scheduler time
//          Tokenize notecard reader, to simplify notecard setup
//          Remove scripted texture changes, to simplify customization by animation sellers

// Fennec Wind, January 18th, 2007:
//          Changed Walk/Sit/Ground Sit dialogs to show animation name (or partial name if too long) 
//          and only show buttons for non-blank entries.
//          Fixed minor bug in the state_entry, ground sits were not being initialized.
//

// Dzonatas Sol, 09/06: Fixed forward walk override (same as previous backward walk fix).

// Based on Francis Chung's Franimation Overrider v1.8

// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.

// CONSTANTS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Default notecard we read on script_entry
string defaultNoteCard "Default";

// List of all the animation states
list animState = [ "Sitting on Ground""Sitting""Striding""Crouching""CrouchWalking",
                   
"Soft Landing""Standing Up""Falling Down""Hovering Down""Hovering Up",
                   
"FlyingSlow""Flying""Hovering""Jumping""PreJumping""Running",
                   
"Turning Right""Turning Left""Walking""Landing""Standing" ];


// Logic change - we now have a list of tokens. The 'overrides' list is the same length as this, 
// i.e. it has one entry per token, *not* one entry per animation. Multiple options for a token 
// are stored as | separated strings in a single list entry. This was done to save memory, and 
// allow a larger number of stands etc. All the xxxIndex variables now refer to the token index, 
// since that's how long 'overrides' is.

// List of internal tokens. This *must* be in the same sequence as the animState list. Note that
// we combine some tokens after the notecard is read (striding/walking, landing/soft landing), etc.
// The publicized tokens list only contains one entry for each pair, but we'll accept both, and
// combine them later
//list tokens = [
//    "[ Sitting On Ground ]",    // 0
//    "[ Sitting ]",              // 1
//    "",                         // 2 - We don't allow Striding as a token
//    "[ Crouching ]",            // 3
//    "[ Crouch Walking ]",       // 4
//    "",                         // 5 - We don't allow Soft Landing as a token
//    "[ Standing Up ]",          // 6
//    "[ Falling ]",              // 7
//    "[ Flying Down ]",          // 8
//    "[ Flying Up ]",            // 9
//    "[ Flying Slow ]",          // 10
//    "[ Flying ]",               // 11
//    "[ Hovering ]",             // 12
//    "[ Jumping ]",              // 13
//    "[ Pre Jumping ]",          // 14
//    "[ Running ]",              // 15
//    "[ Turning Right ]",        // 16
//    "[ Turning Left ]",         // 17
//    "[ Walking ]",              // 18
//    "[ Landing ]",              // 19
//    "[ Standing ]",             // 20
//    "[ Swimming Down ]",        // 21
//    "[ Swimming Up ]",          // 22
//    "[ Swimming Forward ]",     // 23
//    "[ Floating ]",             // 24
//    "[ Typing ]"                // 25
//];
//
//      |       |       |
//      |       |       |
//      V       V       V
//
integer numOverrides 26;       // # of overrides == tokens

// The tokens for which we allow multiple animations
//list multiAnimTokenIndexes = [
//    0,  // "[ Sitting On Ground ]"
//    1,  // "[ Sitting ]"
//    18, // "[ Walking ]"
//    20  // "[ Standing ]"
//];

// Index of interesting animations
integer noAnimIndex     = -1;
integer sitgroundIndex  0;
integer sittingIndex    1;
integer stridingIndex   2;
integer standingupIndex 6;
integer hoverdownIndex  8;
integer hoverupIndex    9;
integer flyingslowIndex 10;
integer flyingIndex     11;
integer hoverIndex      12;
integer walkingIndex    18;
integer standingIndex   20;
integer swimdownIndex   21;
integer swimupIndex     22;
integer swimmingIndex   23;
integer waterTreadIndex 24;
integer typingIndex     25;

// list of animations that have a different value when underwater
list underwaterAnim = [ hoverIndexflyingIndexflyingslowIndexhoverupIndexhoverdownIndex ];

// corresponding list of animations that we override the overrider with when underwater
list underwaterOverride = [ waterTreadIndexswimmingIndexswimmingIndexswimupIndexswimdownIndex];

// This is an ugly hack, because the standing up animation doesn't work quite right
// (SL is borked, this has been bug reported)
// If you play a pose overtop the standing up animation, your avatar tends to get
// stuck in place.
// This is a list of anims that we'll stop automatically
list autoStop = [ 5619 ];
// Amount of time we'll wait before autostopping the animation (set to 0 to turn off autostopping)
float autoStopTime 1.5;

// How long before flipping stand animations
integer standTimeDefault 30;

// How fast we should poll for changed anims (as fast as possible)
// In practice, you will not poll more than 8 times a second.
float timerEventLength 0.25;

// The minimum time between events.
// While timerEvents are scaled automatically by the server, control events are processed
// much more aggressively, and needs to be throttled by this script
float minEventDelay 0.25;

// The key for the typing animation
//      key typingAnim      =       "c541c47f-e0c0-058b-ad1a-d6ae3a4584d9";
// we dont need this right now ;)

// Listen channel for pop-up menu
//
// Mod: Channel will now be generated from owner UUID.
integer listenChannel = -1//-91234;

// GLOBALS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

integer typingStatus FALSE;               // status of avatar typing

integer numTyping;                          // Number of typing anims
integer numStands;                          // Number of stands - needed for auto cycle
integer randomStands FALSE;               // Whether stands cycle randomly
integer curStandIndex;                      // Current stand - needed for cycling
string curStandAnim "";                   // Current Stand animation
string curSitAnim "";                     // Current sit animation
string curWalkAnim "";                    // Current walk animation
string curGsitAnim "";                    // Current ground sit animation
string curTypingAnim "";                  // Current typing animation

list overrides = [];                        // List of animations we override

string  lastAnim "";                      // last Animation we ever played
string  lastAnimSet "";                   // last set of animations we ever played
integer lastAnimIndex 0;                  // index of the last animation we ever played
string  lastAnimState "";                 // last thing llGetAnimation() returned

integer dialogStandTime standTimeDefault;       // How long before flipping stand animations
integer standTime standTimeDefault;       // How long before flipping stand animations

integer animOverrideOn TRUE;              // Is the animation override on?
integer gotPermission  FALSE;             // Do we have animation permissions?

integer listenHandle;                       // Listen handlers - only used for pop-up menu, then turned off

integer haveWalkingAnim FALSE;            // Hack to get it so we face the right way when we walk backwards

integer sitOverride TRUE;                 // Whether we're overriding sit or not
integer typingOverrideOn TRUE;            // Whether we're overriding typing or not
integer typingKill FALSE;                 // Whether we're killing the typing completely
/// Sit Anywhere mod by Marcus Gray
/// just one var to overrider stands... let's see how this works out 0o
integer sitAnywhereOn FALSE;

integer listenState 0;                    // What pop-up menu we're handling now

integer loadInProgress FALSE;             // Are we currently loading a notecard
string  notecardName "";                  // The notecard we're currently reading

key Owner NULL_KEY;

// String constants to save a few bytes
string EMPTY = "";
//
string TIMINGSEPARATOR ":";
//
string SEPARATOR "|";
string TRYAGAIN "Please correct the notecard and try again.";
string S_SIT "Sit override: ";
string S_SIT_AW "Sit anywhere: ";
string S_TYPING "Typing override: ";
string S_TKILL_ON "Typing killer: On - This also removes custom typing animations!";
string S_TKILL_OFF "Typing killer: Off";

//////////////////////////////////////////////////////////////////////////
/// Seamless Sit mod by Moeka Kohime
///
integer em;
list 
temp;
key sit "1a5fe8ac-a804-8a5d-7cbd-56bd83184568";

// CODE
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
/// Seamless Sit mod by Moeka Kohime
integer CheckSit()
{
    if(!
sitOverride)
        return 
FALSE;
    
temp llGetAnimationList(llGetOwner());
    if (
temp==[])
        return 
FALSE;
    if (
llListFindList(temp,[sit])!=-1)
        return 
TRUE;
    return 
FALSE;
}


startAnimationListstring _csvAnims ) {
    list 
anims llCSV2List_csvAnims );
    
integer i;
    for( 
i=0i<llGetListLength(anims); i++ )
    {
//
//  Mod: Get the special timing parameter
        
list newAnim llParseStringKeepNullsllList2String(anims,i) ,
            [
TIMINGSEPARATOR], [""]);
        
string newAnimName llList2String(newAnim0);

        if( 
llGetListLength(newAnim) == )
        {
            
integer newStandTime = (integer)llList2String(newAnim1);
            if( 
newStandTime 0)
                
standTime = (integer)llList2String(newAnim1);
            else
                
llOwnerSay("Found improper custom timing parameter for animation \""newAnimName "\" - The value must be greater 0, please correct this!");
        }
        else
            
standTime dialogStandTime;
//
//
//        llStartAnimation( llList2String(anims,i) );
        
llStartAnimationnewAnimName );
    }
}

stopAnimationListstring _csvAnims ) {
    list 
anims llCSV2List_csvAnims );
    
integer i;
    for( 
i=0i<llGetListLength(anims); i++ )
    {
//
//  Mod: Get the special timing parameter
        
list newAnim llParseStringKeepNullsllList2String(anims,i) ,
            [
TIMINGSEPARATOR], [""]);
        
string newAnimName llList2String(newAnim0);
//
//
//        llStopAnimation( llList2String(anims,i) );
        
llStopAnimationnewAnimName );
    }
}

startNewAnimationstring _animinteger _animIndexstring _state ) {
    if ( 
_anim != lastAnimSet ) {
        
string newAnim;
        if ( 
lastAnim != EMPTY )
            
stopAnimationListlastAnim );
        if ( 
_anim != EMPTY ) {   // Time to play a new animation
             
list newAnimSet llParseStringKeepNulls_anim, [SEPARATOR], [] );
             
newAnim llList2StringnewAnimSet, (integer)llFloor(llFrand(llGetListLength(newAnimSet))) );

             
startAnimationListnewAnim );

            if ( 
llListFindListautoStop, [_animIndex] ) != -) {
                
// This is an ugly hack, because the standing up animation doesn't work quite right
                // (SL is borked, this has been bug reported)
                // If you play a pose overtop the standing up animation, your avatar tends to get
                // stuck in place.
                
if ( lastAnim != EMPTY ) {
                   
stopAnimationListlastAnim );
                   
lastAnim = EMPTY;
                }
                
llSleepautoStopTime );
                
stopAnimationList_anim );
            }
        }
        
lastAnim newAnim;
        
lastAnimSet _anim;
    }
    
lastAnimIndex _animIndex;
    
lastAnimState _state;
}

// Figure out what animation we should be playing right now
animOverride() {
    
string  curAnimState llGetAnimationOwner );
    
integer curAnimIndex;
    
integer underwaterAnimIndex;

    
// Convert the ones we don't handle
    
if ( curAnimState == "Striding" ) {
        
curAnimState "Walking";
    } else if ( 
curAnimState == "Soft Landing" ) {
        
curAnimState "Landing";
    }

    
// Remove the list check, since it only contains one element
    // Check if we need to work around any bugs in llGetAnimation
    // Hack, because, SL really likes to switch between crouch and crouchwalking for no reason
    
if ( curAnimState == "CrouchWalking" ) {
      if ( 
llVecMag(llGetVel()) < .5 )
         
curAnimState "Crouching";
    }

    if ( 
curAnimState == lastAnimState ) {
        
// This conditional not absolutely necessary (In fact it's better if it's not here)
        // But it's good for increasing performance.
        // One of the drawbacks of this performance hack is the underwater animations
        // If you fly up, it will keep playing the "swim up" animation even after you've
        // left the water.
        
if(CheckSit()!=TRUE) {// Seamless Sit
            
em=0;
            return;
        }else{
            if(
em==0){startNewAnimation( EMPTY, noAnimIndexcurAnimState );em=1;}   
        }
    }

    
curAnimIndex        llListFindListanimState, [curAnimState] );
    
underwaterAnimIndex llListFindListunderwaterAnim, [curAnimIndex] );

    
// For all the multi-anims, we know the animation name to play. Send
    // in the actual overrides index, since that's what this function 
    // expects, not the index into the multi-anim list
    
if ( curAnimIndex == standingIndex ) {
        
// Sit Anywhere 
        
if(!sitAnywhereOn) { // if it is'nt enabled we use a stand
            
startNewAnimationcurStandAnimstandingIndexcurAnimState );
        }
        else { 
// Sity Anywhere is ON
            
startNewAnimationcurGsitAnimsitgroundIndexcurAnimState ); 
        }
    }
    else if ( 
curAnimIndex == sittingIndex ) {
        
// Check if sit override is turned off
        
if (( sitOverride == FALSE ) && ( curAnimState == "Sitting" )&&(CheckSit()!=TRUE)) {// Seamless Sit 
            
startNewAnimation( EMPTY, noAnimIndexcurAnimState );
        }
        else {
            if(
CheckSit()==TRUE){// Seamless Sit
            
startNewAnimationcurSitAnimsittingIndexcurAnimState );
            } else {
            
startNewAnimation( EMPTY, noAnimIndexcurAnimState );
            }
        }
    }
    else if ( 
curAnimIndex == walkingIndex ) {
        
startNewAnimationcurWalkAnimwalkingIndexcurAnimState );
    }
    else if ( 
curAnimIndex == sitgroundIndex ) {
        
startNewAnimationcurGsitAnimsitgroundIndexcurAnimState );
    }
    else {
        if ( 
underwaterAnimIndex != -) {
            
// Only call llGetPos if we care about underwater anims
            
vector curPos llGetPos();
            if ( 
llWater(ZERO_VECTOR) > curPos.) {
                
curAnimIndex llList2IntegerunderwaterOverrideunderwaterAnimIndex );
            }
        }
        
startNewAnimationllList2String(overridescurAnimIndex), curAnimIndexcurAnimState );
    }
}

// Switch to the next stand anim
doNextStand(integer fromUI) {                           
    if ( 
numStands 0) {
        if(!
sitAnywhereOn) { //no need to change stands if we're sitting anyways ;)
            
if ( randomStands ) {
                
curStandIndex llFloorllFrand(numStands) );
            } else {
                
curStandIndex = (curStandIndex 1) % numStands;
            }
    
            
curStandAnim findMultiAnimstandingIndexcurStandIndex );
            if ( 
lastAnimState == "Standing" )
                
startNewAnimationcurStandAnimstandingIndexlastAnimState );
    
            if ( 
fromUI == TRUE ) {
                
string newAnimName llList2String(
                    
llParseStringKeepNulls(curStandAnim, [TIMINGSEPARATOR], []), 0);
                
llOwnerSay"Switching to stand '" newAnimName "'." );
            }
        }
    } else {
        if ( 
fromUI == TRUE ) {
            
llOwnerSay"No stand animations configured." );
        }
    }

    
llResetTime();
}

// Start or stop typing animation
typingOverride(integer isTyping) {
    if(
isTyping) {  
        if( 
typingKill ) { // if we totally kill typing anims
            
llStopAnimation("type");
            
typingStatus FALSE;
        }
        else
        {
            
integer curTypingIndex 0;
            if(
numTyping 1) {
                
curTypingIndex llFloorllFrand(numTyping) );
            }
            
curTypingAnim findMultiAnimtypingIndexcurTypingIndex );
            
startAnimationList(curTypingAnim);
        }
    }
    else if( !
typingKill )
    {  
        
stopAnimationList(curTypingAnim);
    }
}

// Displays menu of animation choices
doMultiAnimMenuinteger _animIndexstring _animTypestring _currentAnim )
{
    
// Dialog enhancement - Fennec Wind
    // Fix - a no-mod anim with a long name will break this

    
list anims llParseString2ListllList2String(overrides_animIndex), [SEPARATOR], [] );
    
integer numAnims llGetListLengthanims );
    if ( 
numAnims 12 ) {
        
llOwnerSay"Too many animations, only the first 12 will be displayed.");
        
numAnims 12;
        return;
    }

    list 
buttons = [];
    
integer i;
    
string animNames = EMPTY;
    for ( 
i=0i<numAnimsi++ ) {
        
animNames += "\n" + (string)(i+1) + ". " llList2Stringanims);
        
buttons += [(string)(i+1)];
    }
    
// If no animations were configured, say so and just display an "OK" button
    
if ( animNames == EMPTY ) {
        
animNames "\n\nNo overrides have been configured.";
    }
    
llListenControl(listenHandleTRUE);
    
llDialogOwner"Select the " _animType " animation to use:\n\nCurrently: " _currentAnim animNames
              
buttonslistenChannel );
}

// Returns an animation from the multiAnims
string findMultiAniminteger _animIndexinteger _multiAnimIndex )
{
    list 
animsList llParseString2ListllList2String(overrides_animIndex), [SEPARATOR], [] );
    return 
llList2StringanimsList_multiAnimIndex );
}

// Print free memory. Separate function to save a few bytes
printFreeMemory()
{
    
integer freemem llGetFreeMemory();
    
integer memory = (integer)((float)freemem 100.0 25674.0);
    
llOwnerSay( (string)memory "% memory free ("+(string)freemem+" Byte)." );
}

// Returns true if we should override the current animation
integer checkAndOverride() {
    if ( 
animOverrideOn && gotPermission ) {
        
animOverride();
        return 
TRUE;
    }
    return 
FALSE;
}

// Load all the animation names from a notecard
loadNoteCard() {

    if ( 
llGetInventoryKey(notecardName) == NULL_KEY ) {
        
llOwnerSay"Notecard '" notecardName "' does not exist, or does not have full permissions." );
        
notecardName = EMPTY;
        return;
    }
    
    
loadInProgress TRUE;

    
// Faster events while processing our notecard
    
llMinEventDelay);

    
// Clear out saved override information, since we now allow sparse notecards
    
overrides = [];
    
integer i;
    for ( 
i=0i<numOverridesi++ )
        
overrides += [EMPTY];

    
// Clear out multi-anim info as well, since we may end up with fewer options
    // that the last time
    
curStandIndex 0;
    
curStandAnim = EMPTY;
    
curSitAnim = EMPTY;
    
curWalkAnim = EMPTY;
    
curGsitAnim = EMPTY;

    
// Start reading the data
    
llMessageLinked(LINK_SET0"LOAD_NC|" notecardNameNULL_KEY);
}

// Stop loading notecard
endNotecardLoad()
{
    
loadInProgress FALSE;
    
notecardName = EMPTY;

    
// Restore the minimum event delay
    
llMinEventDelayminEventDelay );
}

// Initialize listeners, and reset some status variables
initialize() {
    
Owner llGetOwner();
    
    
llSetTimerEvent0.0 );

    if ( 
animOverrideOn )
        
llSetTimerEventtimerEventLength );

    
lastAnim = EMPTY;
    
lastAnimSet = EMPTY;
    
lastAnimIndex noAnimIndex;
    
lastAnimState = EMPTY;
    
gotPermission FALSE;

    
// Create new listener, and turn it off
    
if ( listenHandle )
        
llListenRemovelistenHandle );
    
listenHandle llListenlistenChannel, EMPTY, Owner, EMPTY );
    
llListenControllistenHandleFALSE );

    
printFreeMemory();
}

// STATE
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

default {
    
state_entry() {
        
integer i;

        
Owner llGetOwner();

        
// Just a precaution, this shouldn't be on after a reset
        
if ( listenHandle )
            
llListenRemovelistenHandle );

        
// Generate the channel from the owner UUID.
        
listenChannel = ( + (integer)( "0xF" llGetSubStringllGetOwner(), 06) ) );

        
listenHandle llListenlistenChannel, EMPTY, Owner, EMPTY );

        if ( 
llGetAttached() )
            
llRequestPermissionsllGetOwner(), PERMISSION_TRIGGER_ANIMATION|PERMISSION_TAKE_CONTROLS );
        
// populate override list with blanks
        
overrides = [];
        for ( 
i=0i<numOverridesi++ ) {
            
overrides += [ EMPTY ];
        }
        
randomStands FALSE;
        
initialize();
        
notecardName defaultNoteCard;
        
loadInProgress TRUE;
        
loadNoteCard();

        
// turn off the auto-stop anim hack
        
if ( autoStopTime == )
            
autoStop = [];

        
llResetTime();
    }

    
on_rezinteger _code ) {
        
initialize();
    }

    
attachkey _k ) {
        if ( 
_k != NULL_KEY )
            
llRequestPermissionsllGetOwner(), PERMISSION_TRIGGER_ANIMATION|PERMISSION_TAKE_CONTROLS );
    }

    
run_time_permissionsinteger _perm ) {
      if ( 
_perm != (PERMISSION_TRIGGER_ANIMATION|PERMISSION_TAKE_CONTROLS) )
         
gotPermission FALSE;
      else {
         
llTakeControlsCONTROL_BACK|CONTROL_FWDTRUETRUE );
         
gotPermission TRUE;
      }
    }

    
link_messageinteger _senderinteger _numstring _messagekey _id) {
        
        
// Coming from an interface script
        
if ( _message == "ZHAO_RESET" ) {
            
llOwnerSay"Resetting..." );
            
llResetScript();
        
        } else if ( 
_message == "ZHAO_AOON" ) {
            
// AO On
            
llOwnerSay("ON");
            
llSetTimerEventtimerEventLength );
            
animOverrideOn TRUE;
            
checkAndOverride();
        
        } else if ( 
_message == "ZHAO_AOOFF" ) {
            
//AO OFF
            
llOwnerSay("OFF");
            
llSetTimerEvent0.0 );
            
animOverrideOn FALSE;
            
startNewAnimation( EMPTY, noAnimIndexlastAnimState );
            
lastAnim = EMPTY;
            
lastAnimSet = EMPTY;
            
lastAnimIndex noAnimIndex;
            
lastAnimState = EMPTY;
        
        } else if ( 
_message == "ZHAO_SITON" ) {
            
// Turning on sit override
            
sitOverride TRUE;
            
llOwnerSayS_SIT "On" );
            if ( 
lastAnimState == "Sitting" )
                
startNewAnimationcurSitAnimsittingIndexlastAnimState );
        
        } else if ( 
_message == "ZHAO_SITOFF" ) {
            
// Turning off sit override
            
sitOverride FALSE;
            
llOwnerSayS_SIT "Off" );
            if ( 
lastAnimState == "Sitting" )
                
startNewAnimation( EMPTY, noAnimIndexlastAnimState );
        
        } else if ( 
_message == "ZHAO_SITANYWHERE_ON" ) {
            
// Turning on sit anywhre mod
            
sitAnywhereOn TRUE;
            
llOwnerSayS_SIT_AW "On" );
            if ( 
lastAnimState == "Standing" )
                
startNewAnimationcurGsitAnimsitgroundIndexlastAnimState );
        
        } else if ( 
_message == "ZHAO_SITANYWHERE_OFF" ) {
            
// Turning off sit anywhere mod
            
sitAnywhereOn FALSE;
            
llOwnerSayS_SIT_AW "Off" );
            if ( 
lastAnimState == "Standing" )
                
startNewAnimationcurStandAnimstandingIndexlastAnimState );
        
        } else if ( 
_message == "ZHAO_TYPEAO_ON" ) {
            
// Turning on typing override
            
typingOverrideOn TRUE;
            
llOwnerSayS_TYPING "On" );                    
            
typingStatus FALSE;
            
        } else if ( 
_message == "ZHAO_TYPEAO_OFF" ) {
            
// Turning off typing override
            
typingOverrideOn FALSE;
            
llOwnerSayS_TYPING "Off" );
            if ( 
typingStatus && !typingKill ) {
                
stopAnimationList(curTypingAnim);
                
typingStatus FALSE;
            }   
        } else if ( 
_message == "ZHAO_TYPEKILL_ON" ) {
            
// Turning on Typing killer
            
typingKill TRUE;
            
llOwnerSayS_TKILL_ON );        
            
typingStatus FALSE;
        } else if ( 
_message == "ZHAO_TYPEKILL_OFF" ) {
            
// Turning off Typing killer
            
typingKill FALSE;
            
llOwnerSayS_TKILL_OFF );
            
typingStatus FALSE;
        } else if ( 
_message == "ZHAO_RANDOMSTANDS" ) {
            
// Cycling to next stand - sequential or random
            
randomStands TRUE;
            
llOwnerSay"Stand cycling: Random" );
        
        } else if ( 
_message == "ZHAO_SEQUENTIALSTANDS" ) {
            
// Cycling to next stand - sequential or random
            
randomStands FALSE;
            
llOwnerSay"Stand cycling: Sequential" );
        
        } else if ( 
_message == "ZHAO_SETTINGS" ) {
            
// Print settings
            
if ( sitOverride ) {
                
llOwnerSayS_SIT "On" );
            } else {
                
llOwnerSayS_SIT "Off" );
            }
            if ( 
sitAnywhereOn ) {
                
llOwnerSayS_SIT_AW "On" );
            } else {
                
llOwnerSayS_SIT_AW "Off" );
            }
            if ( 
typingOverrideOn ) {
                
llOwnerSayS_TYPING "On" );
            } else {
                
llOwnerSayS_TYPING "Off" );
            }
            if ( 
typingKill ) {
                
llOwnerSayS_TKILL_ON );
            } else {
                
llOwnerSayS_TKILL_OFF );
            }
            if ( 
randomStands ) {
                
llOwnerSay"Stand cycling: Random" );
            } else {
                
llOwnerSay"Stand cycling: Sequential" );
            }
            
llOwnerSay"Stand cycle time: " + (string)dialogStandTime " seconds" );

        } else if ( 
_message == "ZHAO_NEXTSTAND" ) {
            
// Cycling to next stand - sequential or random. This is from UI, so we
            // want feedback
            
doNextStandTRUE );
        
        } else if ( 
llGetSubString(_message014) == "ZHAO_STANDTIME|" ) {
            
// Stand time change
            
dialogStandTime = (integer)llGetSubString(_message15, -1);
            
llOwnerSay"Stand cycle time: " + (string)dialogStandTime " seconds" );
        
        } else if ( 
llGetSubString(_message09) == "ZHAO_LOAD|" ) {
            
// Can't load while we're in the middle of a load
            
if ( loadInProgress == TRUE ) {
                
llOwnerSay"Cannot load new notecard, still reading notecard '" notecardName "'" );
                return;
            }

            
// Notecard menu
            
notecardName llGetSubString(_message10, -1);
            
loadNoteCard();

        } else if ( 
_message == "ZHAO_SITS" ) {
            
// Selecting new sit anim

            // Move these to a common function
            
doMultiAnimMenusittingIndex"Sitting"curSitAnim );

            
listenState 1;

        } else if ( 
_message == "ZHAO_WALKS" ) {
            
// Same thing for the walk

            // Move these to a common function
            
doMultiAnimMenuwalkingIndex"Walking"curWalkAnim );

            
listenState 2;

        } else if ( 
_message == "ZHAO_GROUNDSITS" ) {
            
// And the ground sit

            // Move these to a common function
            
doMultiAnimMenusitgroundIndex"Sitting On Ground"curGsitAnim );

            
listenState 3;
        } 

        
//Notecard read, we get the string sent over and do some tests
        
else if ( llGetSubString(_message011) == "END_NC_LOAD|" ) {
            
//if loading was a success...
            
if(_num) {
                
overrides = [];
                
//convert overrides back to a list
                
overrides llCSV2List(llGetSubString(_message12llStringLength(_message) - 1));
                
// Do we have a walking animation?
                
if ( llList2String(overrideswalkingIndex) != EMPTY ) {
                     
haveWalkingAnim TRUE;
                }
                
// Reset stand, walk, sit and ground-sit anims to first entry
                
curStandIndex 0;
                
numStands llGetListLengthllParseString2List(llList2String(overridesstandingIndex), 
                                             [
SEPARATOR], []) );
                                             
                
numTyping llGetListLengthllParseString2List(llList2String(overridestypingIndex), 
                                             [
SEPARATOR], []) );
    
                
curStandAnim findMultiAnimstandingIndex);
                
curWalkAnim findMultiAnimwalkingIndex);
                
curSitAnim findMultiAnimsittingIndex);
                
curGsitAnim findMultiAnimsitgroundIndex);
    
                
// Clear out the currently playing anim so we play the new one on the next cycle
                
startNewAnimation( EMPTY, noAnimIndexlastAnimState );
                
lastAnim = EMPTY;
                
lastAnimSet = EMPTY;
                
lastAnimIndex noAnimIndex;
                
lastAnimState = EMPTY;
    
                
llOwnerSay"Finished reading notecard '" notecardName "'." );
                
printFreeMemory();    
            }
            
endNotecardLoad();                
        }
    }

    
listeninteger _channelstring _namekey _idstring _message) {
        
// Turn listen off. We turn it on again if we need to present 
        // another menu
        
llListenControl(listenHandleFALSE);

        if ( 
listenState == ) {
            
// Dialog enhancement - Fennec Wind
            // Note that this is within one 'overrides' entry
            
curSitAnim findMultiAnimsittingIndex, (integer)_message );
            if ( 
lastAnimState == "Sitting" ) {
                
startNewAnimationcurSitAnimsittingIndexlastAnimState );
            }
            
llOwnerSay"New sitting animation: " curSitAnim );

        } else if ( 
listenState == ) {
            
// Dialog enhancement - Fennec Wind
            // Note that this is within one 'overrides' entry
            
curWalkAnim findMultiAnimwalkingIndex, (integer)_message );
            if ( 
lastAnimState == "Walking" ) {
                
startNewAnimationcurWalkAnimwalkingIndexlastAnimState );
            }
            
llOwnerSay"New walking animation: " curWalkAnim );

        } else if ( 
listenState == ) {
            
// Dialog enhancement - Fennec Wind
            // Note that this is within one 'overrides' entry
            
curGsitAnim findMultiAnimsitgroundIndex, (integer)_message );
            
// Lowercase 'on' - that's the anim name in SL
            
if ( lastAnimState == "Sitting on Ground" || ( lastAnimState == "Standing" && sitAnywhereOn ) ) {
                
startNewAnimationcurGsitAnimsitgroundIndexlastAnimState );
            }
            
llOwnerSay"New sitting on ground animation: " curGsitAnim );
        }
    }

    
changed(integer _change) {
        if(
_change CHANGED_TELEPORT) {
            
lastAnimSet = EMPTY;
            
lastAnimState = EMPTY;
            
checkAndOverride();
        }
    }

    
collision_startinteger _num ) {
        
checkAndOverride();
    }

    
collisioninteger _num ) {
       
checkAndOverride();
    }

    
collision_endinteger _num ) {
       
checkAndOverride();
    }

    
controlkey _idinteger _levelinteger _edge ) {
        if ( 
_edge ) {
            
// SL tends to mix animations together on forward or backward walk. It could be because
            // of anim priorities. This helps stop the default walking anims, so it won't mix with
            // the desired anim. This also lets the avi turn around on a backwards walk for a more natural
            // look.
            // Reverse the order of the checks, since we'll often get the control key combination, but we
            // may be flying
            
if ( llGetAnimation(Owner) == "Walking" ) {
                if ( 
_level _edge & ( CONTROL_BACK CONTROL_FWD ) ) {
                    if ( 
haveWalkingAnim ) {
                        
llStopAnimation"walk" );
                        
llStopAnimation"female_walk" );
                    }
                }
            }

            
checkAndOverride();
        }
    }

    
timer() {
        
// TYPING AO!!!!!!!!!!!
        
if( numTyping && typingOverrideOn ) {            
            
integer typingTemp llGetAgentInfoOwner ) & AGENT_TYPING// are we typing?
            
if ( typingTemp != typingStatus ) { //status changed since last checked?
                
typingOverridetypingTemp );
                
typingStatus typingTemp;//save the current status.
            
}
        }
        if( 
checkAndOverride() ) {
            
// Is it time to switch stand animations?
            // Stand cycling can be turned off
            
if ( (standTime != 0) && ( llGetTime() > standTime ) ) {
                
// Don't interrupt the typing animation with a stand change. 
                // Not from UI, no feedback
                
if ( !typingStatus )
                    
doNextStandFALSE );
            }
        }
    }