User:Dz/AO
From OpenSimulator
(→Simple Click on/off Variable speed AO demo) |
(→Simple Click on/off Variable speed AO demo) |
||
(5 intermediate revisions by one user not shown) | |||
Line 11: | Line 11: | ||
If you have feedback on script errors, please post it to the page discussion [[User_talk:Dz/AO]] | If you have feedback on script errors, please post it to the page discussion [[User_talk:Dz/AO]] | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
=== Simple Click on/off Variable speed AO demo === | === Simple Click on/off Variable speed AO demo === | ||
− | This is an example of an AO script designed for use in OpenSimulator. | + | This is an example of an AO script designed for use in OpenSimulator. These instructions describe how to make your own AO from scratch. |
− | + | For this example, I use animations found in the Linda Kelly RUGGED male AO. They should be widely available, and you are free to modify the script to use your own. | |
The variable speed option requires that OS functions be enabled and the threat level set appropriately in the region you want to use this in. This script selects a random walk animation from the 3 provided and changes the walk speed to more closely match the animation selected. | The variable speed option requires that OS functions be enabled and the threat level set appropriately in the region you want to use this in. This script selects a random walk animation from the 3 provided and changes the walk speed to more closely match the animation selected. | ||
− | Generate a small cube (0.15, 0.15, 0.15) | + | Step 1. Generate a small cube (0.15, 0.15, 0.15) |
− | Drag copies of the AO animations you want to use into the contents of the cube. | + | Step 2. Drag copies of the AO animations you want to use into the contents of the cube. |
− | Drop this script in the cube. | + | Step 3. Drop this script in the cube. |
<source lang = "lsl"> | <source lang = "lsl"> | ||
Line 144: | Line 31: | ||
// OpenSimian Speed Scalable Animation Override for OpenSimulator 2014 v2.0 | // OpenSimian Speed Scalable Animation Override for OpenSimulator 2014 v2.0 | ||
// | // | ||
− | // Copyright 2014 by | + | // Copyright 2014 by D Osborn. |
// This script is Licensed under the Creative Commons Attribution-Share Alike 3.0 License | // This script is Licensed under the Creative Commons Attribution-Share Alike 3.0 License | ||
Line 608: | Line 495: | ||
</source> | </source> | ||
− | Edit the script to make sure the animation names in the top section match the animation names you added to the cube. | + | Step 5. Edit the script to make sure the animation names in the top section match the animation names you added to the cube. |
− | Adjust the speed values in the walk animation list and below in the section of code that looks like this... ( 1.0 is the default Opensim speed, this is a multiplier) | + | Step 6. Adjust the speed values in the walk animation list and below in the section of code that looks like this... ( 1.0 is the default Opensim speed, this is a multiplier) |
<source lang = "lsl"> | <source lang = "lsl"> | ||
Line 622: | Line 509: | ||
</source> | </source> | ||
− | Rename the cube "MYAO" (something you can find in your inventory) and pick it up. | + | Step 7. Rename the cube "MYAO" (something you can find in your inventory) and pick it up. |
− | Attach it to one of your HUD positions ... | + | Step 8. Attach it to one of your HUD positions ... |
− | Resize and position. | + | Step 9. Resize and position. |
Touch to toggle between on and off. Re-attach or edit and "script reset" to reset. | Touch to toggle between on and off. Re-attach or edit and "script reset" to reset. | ||
+ | |||
+ | === Why you should (probably) NEVER use a Second Life AO script in OpenSimulator === | ||
+ | |||
+ | Chances are, if you are using a Second Life AO script in OpenSim , you are abusing the region server resources, and perpetuating the myth that all AO's are good for is generating lag. There are fundamental differences between the animation events in SecondLife and Opensim that make Second Life AO script overhead unnecessary. | ||
+ | |||
+ | When the GPL'd ZHAO code was written for SL, it was designed to ask the region "what is my current animation state?" multiple times a second. It then compares the returned state to the last one to see if anything has changed, and if it has, it looks up the new animation it needs and starts to play it. Depending on the timer settings it can ask the same question 4 or 5 times a second (which doesn't work well in OpenSim). | ||
+ | |||
+ | Lets look at what happens when you enter a sim and stand, with your AO set for 1/3 second checks, and your stand changing every 20 seconds... | ||
+ | |||
+ | ''Enter sim, Script loads into memory and starts. | ||
+ | |||
+ | ''Script encounters Stand state, activates stand animation, | ||
+ | |||
+ | ''sets stand timer to 20 seconds | ||
+ | |||
+ | ''in the next 20 seconds the script will ask the sim 60 times "are we still standing?" | ||
+ | |||
+ | ''timer elapsed and a new stand animation is triggered | ||
+ | |||
+ | ''in the next 20 seconds the script will ask the sim 60 times "are we still standing?" | ||
+ | |||
+ | ''timer elapses and the stand animation changes... | ||
+ | |||
+ | ''in the next 20 seconds the script will ask the sim 60 times "are we still standing?" | ||
+ | |||
+ | ...That's the first minute. | ||
+ | |||
+ | 180 "extra" sim interruptions to make sure you haven't stopped standing still. | ||
+ | Say 20 of you in the sim with the same AO... That's 3600 "extra" sim interruptions (per minute) to answer your scripts. In the example below, setting the timer event to 0.25 seconds would generate 14000 interruptions per hour for each AO.. For our mythical group of 20, 280,000 "are we still standing" questions per hour versus 6000 events using the modified script... | ||
+ | |||
+ | In OpenSimulator, the design can be much more efficient. The developers have added a CHANGED_ANIMATION parameter to the CHANGED event in OpenSim, so our scripts don't have to ask what the current animation state is, it just needs to handle the changed event when it is notified. These lines of code replace the timer loop that asks the repetitive question by sending a notice to the script when a new animation state is triggered.. Our script is basically these lines.. | ||
+ | <source lang = "lsl"> | ||
+ | changed(integer change) | ||
+ | { | ||
+ | if (change & CHANGED_ANIMATION) | ||
+ | { | ||
+ | WhichAnimType = llGetAnimation(Owner); | ||
+ | StartAnimation(); | ||
+ | LastAnimType = WhichAnimType; | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | Yes, there is still overhead to loading and running the AO script, but with this interrupt driven design we eliminate a vast majority of the overhead and wasted processing time. | ||
+ | |||
+ | === Converting ZHAO scripts to work in OpenSim efficiently === | ||
+ | |||
+ | If you LOVE your ZHAO based AO and HAVE TO HAVE IT in OpenSim, Do us all a favor.. follow these instructions and modify your script. | ||
+ | |||
+ | Step 1. Make sure you have a ZHAO based AO. | ||
+ | |||
+ | Put the AO on the ground and Edit it. Look in the CONTENTS tab. | ||
+ | If you find the scripts ZHAO II CORE, ZHAO II INTERFACE, and notecard named something like ZHAO READ ME, and a notecard named "default", proceed to step 2. | ||
+ | If you did NOT find any of those files, there is a 100% chance that I take no responsibility for you proceeding to step 2. | ||
+ | |||
+ | Step 2. Make a backup copy of the ZHAO II CORE script by dragging it into your scripts folder in your inventory. | ||
+ | |||
+ | Step 3. Edit your ZHAO CORE script and locate the following lines.... | ||
+ | |||
+ | <source lang = "lsl"> | ||
+ | // 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; | ||
+ | </source> | ||
+ | |||
+ | REPLACE WHATEVER NUMBER IS AFTER THE = with 0.0..... so the line looks like this.... | ||
+ | <source lang = "lsl"> | ||
+ | float timerEventLength = 0.0; | ||
+ | </source> | ||
+ | |||
+ | ( If you are interested in calculating the amount of processing you might save... this value of .25 means that your AO checks 4x a second to see what you are up to. | ||
+ | That can mean more than 14,000 "are we still standing" events an hour. In contrast, changing the stand every 12 seconds for an hour, this modified AO script only requires 300 events. ) | ||
+ | |||
+ | |||
+ | Step 4. Local the section of code that handles the CHANGE event.... It should look something like this..... | ||
+ | |||
+ | <source lang = "lsl"> | ||
+ | changed(integer change) | ||
+ | { | ||
+ | if (change & CHANGED_REGION) | ||
+ | { | ||
+ | if(llGetAttached()) | ||
+ | llRequestPermissions( llGetOwner(), PERMISSION_TRIGGER_ANIMATION|PERMISSION_TAKE_CONTROLS ); | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | Add the 2 new lines of code.... | ||
+ | |||
+ | if (change & CHANGED_ANIMATION) | ||
+ | checkAndOverride(); | ||
+ | |||
+ | So it looks like this... | ||
+ | |||
+ | <source lang = "lsl"> | ||
+ | |||
+ | changed(integer change) | ||
+ | { | ||
+ | if (change & CHANGED_REGION) | ||
+ | { | ||
+ | if(llGetAttached()) | ||
+ | llRequestPermissions( llGetOwner(), PERMISSION_TRIGGER_ANIMATION|PERMISSION_TAKE_CONTROLS ); | ||
+ | } | ||
+ | |||
+ | if (change & CHANGED_ANIMATION) | ||
+ | checkAndOverride(); | ||
+ | |||
+ | } | ||
+ | </source> | ||
+ | |||
+ | |||
+ | Step 5. Save your changes to the script, put the AO in your inventory and then attach/wear it again. | ||
+ | If you have problems, replace your modified version of the script with the one you saved in step 2 above. |
Latest revision as of 08:51, 1 July 2022
Contents |
[edit] Animation Override scripts
These are AO scripts I have used or developed over time. Many of them are assembled from bits and pieces of code I have read/seen/fixed/admired. Some of the code snippets appear with permissions, Please do not remove the attributions where they can be found in the comments. The code has been shared, only asking simple consideration. Please respect the wishes of the original authors as I have attempted to do.
These AO designs are NOT compatible with NPCs, as they require a user to touch them to activate.
If you have feedback on script errors, please post it to the page discussion User_talk:Dz/AO
[edit] Simple Click on/off Variable speed AO demo
This is an example of an AO script designed for use in OpenSimulator. These instructions describe how to make your own AO from scratch.
For this example, I use animations found in the Linda Kelly RUGGED male AO. They should be widely available, and you are free to modify the script to use your own.
The variable speed option requires that OS functions be enabled and the threat level set appropriately in the region you want to use this in. This script selects a random walk animation from the 3 provided and changes the walk speed to more closely match the animation selected.
Step 1. Generate a small cube (0.15, 0.15, 0.15)
Step 2. Drag copies of the AO animations you want to use into the contents of the cube.
Step 3. Drop this script in the cube.
// // OpenSimian Speed Scalable Animation Override for OpenSimulator 2014 v2.0 // // Copyright 2014 by D Osborn. // This script is Licensed under the Creative Commons Attribution-Share Alike 3.0 License // For a copy of the license terms please see http://creativecommons.org/licenses/by-sa/3.0 // set the animations as instructed below // Remember to put the animation in the prim... // SpdScale is the float multiplier... 1 is default speed // you can reset default in the grey state if you want a boost/damper when the AO is off // ************************** Customize YOUR AO by changing the names of the Animations, and the cycle time for your stands here. list StandNames = ["rugged-stand-1", "rugged-stand-2", "rugged-stand-3"]; integer StandTime = 8; // change this number to the number of seconds between stands list WalkAnimations = [ "Walk-Male-Fast", 1.1, "Walk-Male-Medium", 1.00, "Walk-Male-Slow", 0.95]; // Change this string to the name of the walk animation you want to use string TrnRight = "AO-TurnRight-Male"; // Change this string to the name of your turn right animation string TrnLeft = "AO-TurnLeft-Male"; // Change this string to the name of your turn left animation string RunAnimation = "run"; // Change this string to the name of the RUN animation you want to use string SitAnimation = "AO-Sit2-Male"; // Change this string to the name of the crouch animation you want to use integer OverrideSit = TRUE; // string CrouchAnimation = "AO-Crouch-Male"; // Change this string to the name of the crouch animation you want to use string CrouchWalkAnimation = "AO-CrouchWalk1-Male"; // Change this string to the name of the crouch walk animation you want to use string FlyAnimation = "AO-Fly1-Male"; // Change this string to the name of the fly animation you want to use string HoverAnimation = "AO-Hover-Male"; // Change this string to the name of the hover animation you want to use string SoftLandAnimation = "AO-Softlanding-Male"; // Change this string to the name of the soft land animation you want to use integer LandingTime = 3; // Change this to reflect the length of the standing animation in seconds. string JumpAnimation = "AO-JumpFlip1-Male"; // Change this string to the name of the jump animation you want to use // ******************************************************************************************************************************* key Owner= NULL_KEY; integer resetflag = 0; vector onColor = <42,255,42>; // all nice and green vector offColor = <128,128,128>; // and grey float WalkSpdScale = 1.0; // default speed scale when OFF float SprintSpdScale = 1.5; float FlySpdScale = 2; string LastAnimType = ""; string LastAnimName = ""; string LastRunAnim = ""; string WhichAnimType = ""; float StandCount = 0.0; // Start Me Up Initialize(key id) { if (id == NULL_KEY) // detaching { llSetTimerEvent(0.0); // stop the timer } else // attached, or reset while worn { Owner = id; llRequestPermissions(id, PERMISSION_TRIGGER_ANIMATION); } StandCount = (float) llGetListLength(StandNames); llSetColor(offColor/255.0, ALL_SIDES); llSay(0,"Initialized"); } StartAnimation() { if (LastAnimType != WhichAnimType) { if (WhichAnimType == "Walking") { llStopAnimation(LastAnimName); if(WalkAnimations != []) { list RndWalk = llListRandomize(WalkAnimations,2); LastAnimName = llList2String(RndWalk,0); osSetSpeed(Owner,llList2Float(RndWalk,1)); // llSay(0,LastAnimName); llStartAnimation(LastAnimName); } llSetTimerEvent(0); } if (WhichAnimType == "Running") { llStopAnimation(LastAnimName); if(RunAnimation != "") { LastAnimName = RunAnimation; llStartAnimation(LastAnimName); } osSetSpeed(Owner,SprintSpdScale); llSetTimerEvent(0); } if (WhichAnimType == "Standing") { llStopAnimation(LastAnimName); if(StandCount > 0.0) { integer whichone = (integer)llFrand(StandCount);// pick a new stand LastAnimName = llList2String (StandNames,whichone); llStartAnimation(LastAnimName); llSetTimerEvent(StandTime); } else { llSetTimerEvent(0); } } if (WhichAnimType == "Sitting") { llStopAnimation(LastAnimName); if(SitAnimation != "" && OverrideSit) { LastAnimName = SitAnimation; llStartAnimation(LastAnimName); } llSetTimerEvent(0); } if (WhichAnimType == "Flying") { llStopAnimation(LastAnimName); if(FlyAnimation != "") { LastAnimName = FlyAnimation; llStartAnimation(LastAnimName); } osSetSpeed(Owner, FlySpdScale); llSetTimerEvent(0); } if (WhichAnimType == "Hovering") { llStopAnimation(LastAnimName); if(HoverAnimation != "") { LastAnimName = HoverAnimation; llStartAnimation(LastAnimName); } llSetTimerEvent(0); } if (WhichAnimType == "Soft Landing") { llStopAnimation(LastAnimName); if(SoftLandAnimation != "") { LastAnimName = SoftLandAnimation; llStartAnimation(LastAnimName); llSetTimerEvent(LandingTime); } llSetTimerEvent(0); } if (WhichAnimType == "Crouching") { llStopAnimation(LastAnimName); if(CrouchAnimation != "") { LastAnimName = CrouchAnimation; llStartAnimation(LastAnimName); } llSetTimerEvent(0); } if (WhichAnimType == "Crouch Walking") { llStopAnimation(LastAnimName); if(CrouchWalkAnimation != "") { LastAnimName = CrouchWalkAnimation; llStartAnimation(LastAnimName); } llSetTimerEvent(0); } if (WhichAnimType == "Jumping") { llStopAnimation(LastAnimName); if(JumpAnimation != "") { LastAnimName = JumpAnimation; llStartAnimation(LastAnimName); } llSetTimerEvent(0); } if (WhichAnimType == "Turning Right") { llStopAnimation(LastAnimName); if(TrnRight != "") { LastAnimName = TrnRight; llStartAnimation(LastAnimName); } llSetTimerEvent(0); } if (WhichAnimType == "Turning Left") { llStopAnimation(LastAnimName); if(TrnLeft != "") { LastAnimName = TrnLeft; llStartAnimation(LastAnimName); } llSetTimerEvent(0); } } } default { state_entry() { if (llGetAttached() != 0) { Initialize(llGetOwner()); } } on_rez(integer start_param) { // Restarts the script every time the object is rezzed llResetScript(); } attach(key id) { Initialize(id); } run_time_permissions(integer perm) { if (perm & PERMISSION_TRIGGER_ANIMATION) { state off; } } changed(integer change) { if (change & CHANGED_INVENTORY) { resetflag = 1; llSetTimerEvent(15); } if (change & CHANGED_REGION_RESTART) { llResetScript(); } } timer() { if(resetflag ==1) llResetScript(); } state_exit() { // llSay(0, "The script leaves the default state."); } } state on { state_entry() { llSetColor(onColor/255.0, ALL_SIDES); osSetSpeed(Owner,WalkSpdScale); llSay(0,"Touch to disable"); WhichAnimType = llGetAnimation(Owner); StartAnimation(); LastAnimType = WhichAnimType; } touch_end(integer num_detected) { state off; } changed(integer change) { if (change & CHANGED_ANIMATION) { WhichAnimType = llGetAnimation(Owner); StartAnimation(); LastAnimType = WhichAnimType; } if (change & CHANGED_INVENTORY) { resetflag = 1; llSetTimerEvent(15); } if (change & CHANGED_REGION_RESTART) { llResetScript(); } } timer() { if(resetflag ==1) llResetScript(); llStopAnimation(LastAnimName); integer whichone = (integer)llFrand(StandCount); // pick the new stand at random LastAnimName = llList2String (StandNames,whichone); llStartAnimation(LastAnimName); // llOwnerSay( "using " + LastAnimName); // uncomment this to see which stand gets trigger by the timer llSetTimerEvent(StandTime); } state_exit() { llStopAnimation(LastAnimName); } } state off { state_entry() { llSetColor(offColor/255.0, ALL_SIDES); osSetSpeed(Owner,1.0); llOwnerSay("Touch to enable"); } touch_end(integer num_detected) { state on; } changed(integer change) { if (change & CHANGED_INVENTORY) { resetflag = 1; llSetTimerEvent(15); } if (change & CHANGED_REGION_RESTART) { llResetScript(); } } timer() { if(resetflag ==1) llResetScript(); } state_exit() { LastAnimType = ""; // should trigger the new animation to start, even if it was the same when we turned it off } }
Step 5. Edit the script to make sure the animation names in the top section match the animation names you added to the cube.
Step 6. Adjust the speed values in the walk animation list and below in the section of code that looks like this... ( 1.0 is the default Opensim speed, this is a multiplier)
list WalkAnimations = [ "Walk-Male-Fast", 1.1, "Walk-Male-Medium", 1.00, "Walk-Male-Slow", 0.95]; // Change this string to the name of the walk animation you want to use ... float WalkSpdScale = 1.0; // default speed scale when OFF float SprintSpdScale = 1.5; float FlySpdScale = 2;
Step 7. Rename the cube "MYAO" (something you can find in your inventory) and pick it up.
Step 8. Attach it to one of your HUD positions ...
Step 9. Resize and position.
Touch to toggle between on and off. Re-attach or edit and "script reset" to reset.
[edit] Why you should (probably) NEVER use a Second Life AO script in OpenSimulator
Chances are, if you are using a Second Life AO script in OpenSim , you are abusing the region server resources, and perpetuating the myth that all AO's are good for is generating lag. There are fundamental differences between the animation events in SecondLife and Opensim that make Second Life AO script overhead unnecessary.
When the GPL'd ZHAO code was written for SL, it was designed to ask the region "what is my current animation state?" multiple times a second. It then compares the returned state to the last one to see if anything has changed, and if it has, it looks up the new animation it needs and starts to play it. Depending on the timer settings it can ask the same question 4 or 5 times a second (which doesn't work well in OpenSim).
Lets look at what happens when you enter a sim and stand, with your AO set for 1/3 second checks, and your stand changing every 20 seconds...
Enter sim, Script loads into memory and starts.
Script encounters Stand state, activates stand animation,
sets stand timer to 20 seconds
in the next 20 seconds the script will ask the sim 60 times "are we still standing?"
timer elapsed and a new stand animation is triggered
in the next 20 seconds the script will ask the sim 60 times "are we still standing?"
timer elapses and the stand animation changes...
in the next 20 seconds the script will ask the sim 60 times "are we still standing?"
...That's the first minute.
180 "extra" sim interruptions to make sure you haven't stopped standing still. Say 20 of you in the sim with the same AO... That's 3600 "extra" sim interruptions (per minute) to answer your scripts. In the example below, setting the timer event to 0.25 seconds would generate 14000 interruptions per hour for each AO.. For our mythical group of 20, 280,000 "are we still standing" questions per hour versus 6000 events using the modified script...
In OpenSimulator, the design can be much more efficient. The developers have added a CHANGED_ANIMATION parameter to the CHANGED event in OpenSim, so our scripts don't have to ask what the current animation state is, it just needs to handle the changed event when it is notified. These lines of code replace the timer loop that asks the repetitive question by sending a notice to the script when a new animation state is triggered.. Our script is basically these lines..
changed(integer change) { if (change & CHANGED_ANIMATION) { WhichAnimType = llGetAnimation(Owner); StartAnimation(); LastAnimType = WhichAnimType; } }
Yes, there is still overhead to loading and running the AO script, but with this interrupt driven design we eliminate a vast majority of the overhead and wasted processing time.
[edit] Converting ZHAO scripts to work in OpenSim efficiently
If you LOVE your ZHAO based AO and HAVE TO HAVE IT in OpenSim, Do us all a favor.. follow these instructions and modify your script.
Step 1. Make sure you have a ZHAO based AO.
Put the AO on the ground and Edit it. Look in the CONTENTS tab. If you find the scripts ZHAO II CORE, ZHAO II INTERFACE, and notecard named something like ZHAO READ ME, and a notecard named "default", proceed to step 2. If you did NOT find any of those files, there is a 100% chance that I take no responsibility for you proceeding to step 2.
Step 2. Make a backup copy of the ZHAO II CORE script by dragging it into your scripts folder in your inventory.
Step 3. Edit your ZHAO CORE script and locate the following lines....
// 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;
REPLACE WHATEVER NUMBER IS AFTER THE = with 0.0..... so the line looks like this....
float timerEventLength = 0.0;
( If you are interested in calculating the amount of processing you might save... this value of .25 means that your AO checks 4x a second to see what you are up to. That can mean more than 14,000 "are we still standing" events an hour. In contrast, changing the stand every 12 seconds for an hour, this modified AO script only requires 300 events. )
Step 4. Local the section of code that handles the CHANGE event.... It should look something like this.....
changed(integer change) { if (change & CHANGED_REGION) { if(llGetAttached()) llRequestPermissions( llGetOwner(), PERMISSION_TRIGGER_ANIMATION|PERMISSION_TAKE_CONTROLS ); } }
Add the 2 new lines of code....
if (change & CHANGED_ANIMATION) checkAndOverride();
So it looks like this...
changed(integer change) { if (change & CHANGED_REGION) { if(llGetAttached()) llRequestPermissions( llGetOwner(), PERMISSION_TRIGGER_ANIMATION|PERMISSION_TAKE_CONTROLS ); } if (change & CHANGED_ANIMATION) checkAndOverride(); }
Step 5. Save your changes to the script, put the AO in your inventory and then attach/wear it again.
If you have problems, replace your modified version of the script with the one you saved in step 2 above.