Edie_Shoreland icon

BotZHAO/Revised llSetAO ZHAO

Edie_Shoreland | PRO | 08/31/18 09:32:51 AM UTC | 0 ⭐ | 8910 👁️ | Never ⏰ | []
Linden Scripting |

0 B

|

None

|

0 👍

/

0 👎

// :CATEGORY:AO
// :NAME:ZHAO-II AO for Second life
// :AUTHOR:Chloe1982 Constantine and others
// :CREATED:2014-01-30 19:59:33
// :EDITED:2014-01-30 19:59:33
// :ID:1016
// :NUM:1572
// :REV:1.0
// :WORLD:Second Life
// :DESCRIPTION:
// ZHAO=II compatible AO using the new LSL Animation functions, timer is now used only to detect swimming
// :CODE:
// As an exercise, I took a version of ZHAO II core and rewrote it to be compatible with a linked message interface, but used the new functions;
// It still needs to poll for swimming but I figured that could be done at a much slower rate than normally used in an AO.
// I had to forgo the ability to replace the typing anim since that would require a faster timer.
//  The new animation override functions don't allow for stacking anims in the way you used to with the , separator so that was given up.
// Finally, in the interests of cramming the core into a single 16k LSL compiled script I didn't implement the timing option for the different anims;
// it could certainly be done, I just chose not to do so!
 
 
// ZHAO-II-core - Ziggy Puff, 07/07
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Evie Moriguchi/Edie Shoreland, 10/05/15 - Allow (but ignore) any [ Typing ] animations
//                   included in notecards without the script sending an error message.
//                   [No need to edit the "Default" notecard, Making it easier to dump ZHAO 
//                   contents from an older ZHAO into a bot friendly single prim style AO.
//                   Put all animations (including the typing ones), this script, and the
//                   unedited "Default" notecard into a prim and reset the script.]
//                   Fixed so sitOverride == FALSE actually turns off the sitting override
//                   [Sit Override OFF is just the better option for bots and NPCs, no more
//                   weird glitchy sits while two priority 3 animations fight it out.]
//
// Chloe1982 Constantine, 05/08/13 - Modified/Updated to use the new LSL Animation functions, timer is
//                   now used only to detect swimming (timerEventLength)
//
// 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.
 
/////////////////////////////////////////////////////////////////////////////////////////////////////
// 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
//
// 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 ]
//
 
 
// 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", "Taking Off" ];
 
// 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", "Sitting",     "Striding", "Crouching", "Crouch Walking",        // 0-4
                "Soft Landing", "Standing Up", "Falling", "Flying Down", "Flying Up",            // 5-9
                "Flying Slow", "Flying", "Hovering", "Jumping", "Pre Jumping",                    // 10-14
                "Running", "Turning Right", "Turning Left", "Walking", "Landing",                // 15-19
                "Standing", "Taking Off", "Swimming Down", "Swimming Up", "Swimming Forward",    // 20-24
                "Floating" ];                                                                    // 25
 
// The tokens for which we allow multiple animations
string multiAnimTokenIndexes = ",0,1,18,20,";    // Groundsit, Sitting, Walking, Standing
 
// Index of interesting animations
integer noAnimIndex     = -1;
integer sitgroundIndex  = 0;
integer sittingIndex    = 1;
/*
integer hoverdownIndex  = 8;
integer hoverupIndex    = 9;
integer flyingslowIndex = 10;
integer flyingIndex     = 11;
integer hoverIndex      = 12;
*/
integer walkingIndex    = 18;
integer standingIndex   = 20;
/*
integer swimdownIndex   = 22;
integer swimupIndex     = 23;
integer swimmingIndex   = 24;
integer waterTreadIndex = 25;
*/
 
// magic string that replaces the following commented out lists
string magicPos = "12111009082524242322";
// number of swimming replacement anims
integer magicSwim = 5;
 
// list of animations that have a different value when underwater
//list underwaterAnim = [ hoverIndex, flyingIndex, flyingslowIndex, hoverupIndex, hoverdownIndex ];
 
// corresponding list of animations that we override the overrider with when underwater
//list underwaterOverride = [ waterTreadIndex, swimmingIndex, swimmingIndex, swimupIndex, swimdownIndex];
 
// How long before flipping stand animations
integer standTimeDefault = 30;
 
// How fast should we poll for whether or not we're under water?
// NOTE, you can change this to whatever value you like, it will just change the delay on how long it takes
// you to start/stop swimming
 
float timerEventLength = 3.0;
 
// Number of timer events that will have to pass to change an anim
integer maxTicks;
// Number of ticks that have passed
integer numTicks = 0;
// Are we underwater?
integer    isUnder = FALSE;
 
// Listen channel for pop-up menu
integer listenChannel = -91234;
 
// GLOBALS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
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
 
list overrides = [];                        // List of animations we override
key notecardLineKey;                        // notecard reading keys
integer notecardIndex;                      // current line being read from notecard
integer numOverrides;                       // # of overrides
 
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 = FALSE;                 // Whether we're overriding sit or not
 
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 SEPARATOR = "|";
string TRYAGAIN = "\nPlease correct the notecard and try again.";
 
// CODE
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
// Enable or disable the AO
 
AO_Enable()
{
    llSetTimerEvent(timerEventLength);
    numTicks = 0;
    if (gotPermission)
        sendOverrides();
}
 
AO_Disable()
{
    llSetTimerEvent(0.0);
    if (gotPermission)
        llResetAnimationOverride("ALL");            // Clear them all out
}
 
// Send new overrides to the server
sendOverrides()
{
    integer n = llGetListLength(animState);
    string anim = EMPTY;
    string st;
    while (n--)
    {
        st = llList2String(animState, n);
        if ((anim = llList2String(overrides, n)) == EMPTY)
            llResetAnimationOverride(st);
        else if (llSubStringIndex(multiAnimTokenIndexes, "," + (string)n + ",") == -1)
            doAnimSet(st, anim);
        else
        {
            if (n == 0)
                anim = curGsitAnim;
            else if (n == 1)
                anim = curSitAnim;
            else if (n == 18)
                anim = curWalkAnim;
            else
                anim = curStandAnim;
            doAnimSet(st, anim);
        }
    }
}
 
// Switch to the next stand anim
doNextStand(integer fromUI)
{
    if (numStands > 0)
    {
        if (randomStands)
            curStandIndex = llFloor(llFrand(numStands));
        else
            curStandIndex = (curStandIndex + 1) % numStands;
 
        doAnimSet("Standing", curStandAnim = findMultiAnim(20, curStandIndex));  //, 20
 
        if (fromUI)
            llOwnerSay("Switching to stand '" + curStandAnim + "'.");
    }
    else if (fromUI)
        llOwnerSay("No stand animations configured.");
}
 
// Actually set the animation (if we need to)
// Fixed so sitOverride can actually be turned off
doAnimSet(string st, string anim)
{
    if (anim == EMPTY)
        return;
    if (animOverrideOn)
    {
        if (sitOverride == TRUE) llSetAnimationOverride(st, anim);
        else if (st != "Sitting") llSetAnimationOverride(st, anim);
    }
}
 
// Displays menu of animation choices
doMultiAnimMenu( integer _animIndex, string _animType, string _currentAnim )
{
    // Dialog enhancement - Fennec Wind
    // Fix - a no-mod anim with a long name will break this
 
    list anims = llParseString2List( llList2String(overrides, _animIndex), [SEPARATOR], [] );
    integer numAnims = llGetListLength( anims );
    if ( numAnims > 12 ) {
        llOwnerSay( "Too many animations, cannot generate menu. " + TRYAGAIN );
        return;
    }
 
    list buttons = [];
    integer i;
    string animNames = EMPTY;
    for ( i=0; i<numAnims; i++ ) {
        animNames += "\n" + (string)(i+1) + ". " + llList2String( anims, i );
        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(listenHandle, TRUE);
    llDialog( Owner, "Select the " + _animType + " animation to use:\n\nCurrently: " + _currentAnim + animNames,
              buttons, listenChannel );
}
 
// Returns an animation from the multiAnims
string findMultiAnim( integer _animIndex, integer _multiAnimIndex )
{
    list animsList = llParseString2List( llList2String(overrides, _animIndex), [SEPARATOR], [] );
    return llList2String( animsList, _multiAnimIndex );
}
 
// Checks for too many animations - can't do menus with > 12 animations
checkMultiAnim( integer _animIndex, string _animName )
{
    list animsList = llParseString2List( llList2String(overrides, _animIndex), [SEPARATOR], [] );
    if ( llGetListLength(animsList) > 12 )
        llOwnerSay( "You have more than 12 " + _animName + " animations. Please correct this." );
}
 
checkAnimInInventory( string _csvAnims )
{
    list anims = llCSV2List( _csvAnims );
    integer i;
    for( i=0; i<llGetListLength(anims); i++ ) {
        string animName = llList2String( anims, i );
        if ( llGetInventoryType( animName ) != INVENTORY_ANIMATION ) {
            // Only a warning, so built-in anims can be used
            llOwnerSay( "Warning: Couldn't find animation '" + animName + "' in inventory." );
        }
    }
}
 
// Print free memory. Separate function to save a few bytes
printFreeMemory()
{
    float memory = (float)llGetFreeMemory() * 100.0 / 16384.0;
    llOwnerSay( (string)((integer)memory) + "% memory free" );
}
 
doWater(integer drowning)
{
    if (isUnder == drowning)
        return;
    integer n = magicSwim;
    integer off = 0;
    if (isUnder = drowning)
        off = 2 * n;
 
    integer p;
    integer po;
    string anim;
    string st;
    while (n--)
    {
        po = p = (integer)llGetSubString(magicPos, n * 2, n * 2 + 1);
        if (isUnder)
            po = (integer)llGetSubString(magicPos, n * 2 + off, n * 2 + 1 + off);
        st = llList2String(animState, p);
        if ((anim = llList2String(overrides, po)) == EMPTY)
            llResetAnimationOverride(st);
        else
            doAnimSet(st, anim);
    }
}
 
// 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." );
        loadInProgress = FALSE;
        notecardName = EMPTY;
        return;
    }
 
    llOwnerSay( "Loading notecard '" + notecardName + "'..." );
 
    // Faster events while processing our notecard
    llMinEventDelay( 0 );
 
    // Clear out saved override information, since we now allow sparse notecards
    overrides = [];
    integer i;
    for ( i=0; i<numOverrides; i++ )
        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
    notecardIndex = 0;
    notecardLineKey = llGetNotecardLine( notecardName, notecardIndex );
}
 
// Stop loading notecard
endNotecardLoad()
{
    loadInProgress = FALSE;
    notecardName = EMPTY;
}
 
// Initialize listeners, and reset some status variables
initialize() {
    Owner = llGetOwner();
 
    float tevent = 0.0;
    if (animOverrideOn)
        tevent = standTime;
    llSetTimerEvent(tevent);
    numTicks = 0;
    maxTicks = llRound(standTime / timerEventLength);
 
    gotPermission = FALSE;
 
    // Create new listener, and turn it off
    if ( listenHandle )
        llListenRemove( listenHandle );
 
    listenHandle = llListen( listenChannel, EMPTY, Owner, EMPTY );
    llListenControl( listenHandle, FALSE );
 
    printFreeMemory();
}
 
// STATE
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
default {
    state_entry() {
        integer i;
 
        Owner = llGetOwner();
 
        // Just a precaution, this shouldn't be on after a reset
        if ( listenHandle )
            llListenRemove( listenHandle );
 
        listenHandle = llListen( listenChannel, EMPTY, Owner, EMPTY );
 
        if (llGetAttached())
            llRequestPermissions(Owner, PERMISSION_OVERRIDE_ANIMATIONS);
 
        numOverrides = llGetListLength(tokens);
 
        // populate override list with blanks
        overrides = [];
        for ( i=0; i<numOverrides; i++ ) {
            overrides += [ EMPTY ];
        }
        randomStands = FALSE;
        initialize();
        notecardName = defaultNoteCard;
        loadInProgress = TRUE;
        loadNoteCard();
    }
 
    on_rez( integer _code ) {
        initialize();
    }
 
    attach( key _k ) {
        if (_k != NULL_KEY)
            llRequestPermissions(Owner, PERMISSION_OVERRIDE_ANIMATIONS);
        else if (gotPermission)
            llResetAnimationOverride("ALL");
        gotPermission = FALSE;
    }
 
    run_time_permissions( integer _perm ) {
        if (_perm & PERMISSION_OVERRIDE_ANIMATIONS)
        {
            if (animOverrideOn)
                sendOverrides();
            gotPermission = TRUE;
        }
    }
 
    link_message( integer _sender, integer _num, string _message, key _id) {
 
        // Coming from an interface script
        if ( _message == "ZHAO_RESET" ) {
            llOwnerSay( "Resetting..." );
            llResetScript();
 
        } else if ( _message == "ZHAO_AOON" ) {
            animOverrideOn = TRUE;
            llOwnerSay("AO Enabled.");
            AO_Enable();
 
        } else if ( _message == "ZHAO_AOOFF" ) {
            animOverrideOn = FALSE;
            llOwnerSay("AO Disabled.");
            AO_Disable();
 
        } else if ( _message == "ZHAO_SITON" ) {
            // Turning on sit override
            sitOverride = TRUE;
            llOwnerSay("Sit override: On");
            doAnimSet("Sitting", curSitAnim);
 
        } else if ( _message == "ZHAO_SITOFF" ) {
            // Turning off sit override
            sitOverride = FALSE;
            llOwnerSay("Sit override: Off");
            llResetAnimationOverride("Sitting");
 
        } 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 == TRUE ) {
                llOwnerSay( "Sit override: On" );
            } else {
                llOwnerSay( "Sit override: Off" );
            }
            if ( randomStands == TRUE ) {
                llOwnerSay( "Stand cycling: Random" );
            } else {
                llOwnerSay( "Stand cycling: Sequential" );
            }
            llOwnerSay( "Stand cycle time: " + (string)standTime + " seconds" );
 
        } else if ( _message == "ZHAO_NEXTSTAND" ) {
            // Cycling to next stand - sequential or random. This is from UI, so we
            // want feedback
            doNextStand( TRUE );
 
        } else if ( llGetSubString(_message, 0, 14) == "ZHAO_STANDTIME|" ) {
            // Stand time change
            maxTicks = llRound((standTime = (integer)llGetSubString(_message, 15, -1)) / timerEventLength);
            llOwnerSay( "Stand cycle time: " + (string)standTime + " seconds" );
 
        } else if ( llGetSubString(_message, 0, 9) == "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
            loadInProgress = TRUE;
            notecardName = llGetSubString(_message, 10, -1);
            loadNoteCard();
 
        } else if ( _message == "ZHAO_SITS" ) {
            // Selecting new sit anim
 
            // Move these to a common function
            doMultiAnimMenu( sittingIndex, "Sitting", curSitAnim );
 
            listenState = 1;
 
        } else if ( _message == "ZHAO_WALKS" ) {
            // Same thing for the walk
 
            // Move these to a common function
            doMultiAnimMenu( walkingIndex, "Walking", curWalkAnim );
 
            listenState = 2;
        } else if ( _message == "ZHAO_GROUNDSITS" ) {
            // And the ground sit
 
            // Move these to a common function
            doMultiAnimMenu( sitgroundIndex, "Sitting On Ground", curGsitAnim );
 
            listenState = 3;
        }
    }
 
    listen( integer _channel, string _name, key _id, string _message) {
        // Turn listen off. We turn it on again if we need to present
        // another menu
        llListenControl(listenHandle, FALSE);
 
        if ( listenState == 1 ) {
            doAnimSet("Sitting", curSitAnim = findMultiAnim(1, (integer)_message - 1));
            llOwnerSay("New sitting animation: " + curSitAnim);
 
        } else if ( listenState == 2 ) {
            doAnimSet("Walking", curWalkAnim = findMultiAnim(18, (integer)_message - 1));
            llOwnerSay("New walking animation: " + curWalkAnim);
 
        } else if ( listenState == 3 ) {
            doAnimSet("Sitting on Ground", curGsitAnim = findMultiAnim(0, (integer)_message - 1));
            llOwnerSay("New groundsit animation: " + curGsitAnim);
        }
    }
 
    dataserver( key _query_id, string _data )
    {
        if ( _query_id != notecardLineKey )
            return;
 
        if ( _data == EOF )
        {
            // Now the read ends when we hit EOF
 
            // End-of-notecard handling...
 
            // See how many walks/sits/ground-sits we have
            checkMultiAnim(18, "walking");
            checkMultiAnim(1, "sitting");
 
            // Reset stand, walk, sit and ground-sit anims to first entry
            curStandIndex = 0;
            numStands = llGetListLength(llParseString2List(llList2String(overrides, 20), (list)SEPARATOR, [])); //FIX
 
            curStandAnim = findMultiAnim(20, 0);
            curWalkAnim = findMultiAnim(18, 0);
            curSitAnim = findMultiAnim(1, 0);
 
            endNotecardLoad();
            llOwnerSay("LSL Functions/AO loaded. Mem:" + (string)llGetFreeMemory());
 
            return;
        }
 
        // We ignore blank lines and lines which start with a #
        // Accept (and ignore) [ Typing ] entries in default notecards  
        if (_data == EMPTY || llGetSubString(_data, 0, 0) == "#" || llGetSubString(_data, 0, 9) == "[ Typing ]")
        {
            notecardLineKey = llGetNotecardLine(notecardName, ++notecardIndex);
            return;
        }
 
        // Let's get a token
        integer p = llSubStringIndex(_data, "[");
        string token = EMPTY;
        string anims = EMPTY;
        if (p != -1)
        {
            if ((p = llSubStringIndex(_data = llDeleteSubString(_data, 0, p), "]")) != -1)
            {
                token = llStringTrim(llGetSubString(_data, 0, p - 1), STRING_TRIM);
                anims = llStringTrim(llDeleteSubString(_data, 0, p), STRING_TRIM);
                if ((p = llListFindList(tokens, [token])) == -1)
                {
                    llOwnerSay("AO:bad data on line " + (string)(notecardIndex+1) + " of " + notecardName + TRYAGAIN); // start from 1
                    endNotecardLoad();
                    return;
                }
            }
        }
 
        if (anims != EMPTY)
        {
            // See if this is a token for which we allow multiple animations
            if (llSubStringIndex(multiAnimTokenIndexes, "," + (string)p + ",") != -1)
            {  //FIX
                list anims2Add = llParseString2List(anims, (list)SEPARATOR, []); //FIX
                // Make sure the anims exist
                integer k = llGetListLength(anims2Add);
                while (k--)
                    checkAnimInInventory(llList2String(anims2Add, k));
 
                // Join the string and list and put it back into overrides
                overrides = llListReplaceList(overrides, (list)(llList2String(overrides, p) + SEPARATOR + llDumpList2String(anims2Add, SEPARATOR)), p, p ); //FIX
            }
            else
            {
                // This is an animation for which we only allow one override
                if (llSubStringIndex(anims, SEPARATOR) != -1)
                {
                    llOwnerSay("Multiple anims for " + token + " not allowed. " + TRYAGAIN);
                    endNotecardLoad();
                    return;
                }
 
                // Inventory check
                checkAnimInInventory(anims);
 
                // We're good
                overrides = llListReplaceList(overrides, (list)anims, p, p); //FIX
            }
        }
 
        // Wow, after all that, we read one line of the notecard
        notecardLineKey = llGetNotecardLine(notecardName, ++notecardIndex);
    }
 
    timer() {
        vector cur = llGetPos();
        doWater(cur.z < llWater(ZERO_VECTOR));
        if (!(numTicks = (numTicks + 1) % maxTicks))
        {
            if (llGetAnimation(Owner) == "Standing")
                doNextStand(FALSE);
        }
    }
}

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎