Smooth Rotating Door

Smooth Rotating Door Script
==Introduction==
Most doors in SL use the same method for opening. They set the door's rotation in one or more steps, resulting in a somewhat choppy motion. This script uses a mixture of llTargetOmega() and llSetLocalRot() to achieve a very smooth, pleasant looking animation for the door. In laggy environments it might be that the script displays a somewhat flaky behavior, but for most cases it will work nicely.
For those unfamiliar with the typical swinging door, you use a box and do a path cut 0.375 / 0.875 to remove one-half of the prim. This will make appear as if it is swinging on its edge and not around it's middle.
// Smooth Door Script - Version 1.2.1
// by Toy Wylie
// Distributed under the following licence:
// - You can use it in your own works
// - You can sell it with your work
// - This script must remain full permissions
// - This header notice must remain intact
// - You may modify this script as needed
float openingTime=3.0; // in seconds
float openingAngle=90.0; // in degrees
float autocloseTime=15.0; // in seconds
integer steps=4; // number of internal rotation steps
integer world=TRUE; // align to world or root prim rotation
string soundOpen="door_open";
string soundClose="door_close";
string soundClosing="door_closing";
float omega=0.0;
vector axis;
rotation closedRot;
rotation openRot;
integer swinging;
integer open;
sound(string name)
{
 if(llGetInventoryType(name)==INVENTORY_SOUND)
 llTriggerSound(name,1.0);
}
openDoor(integer yes)
{
 if(yes)
 sound(soundOpen);
 else
 sound(soundClosing);
 vector useAxis=axis;
 open=yes;
 if(!yes)
 useAxis=-axis;
 llSetTimerEvent(openingTime/(float) steps);
 llTargetOmega(useAxis,omega,1.0);
}
go()
{
 if(swinging==0)
 {
 if(!open)
 {
 axis=<0.0,0.0,1.0>/llGetRootRotation();
 closedRot=llGetLocalRot();
 if(world)
 openRot=llGetRot()*llEuler2Rot(<0.0,0.0,openingAngle>*DEG_TO_RAD)/llGetRootRotation();
 else
 openRot=closedRot*llEuler2Rot(<0.0,0.0,openingAngle>*DEG_TO_RAD);
 }
 swinging=steps;
 openDoor(!open);
 }
}
rotation slerp(rotation source,rotation target,float amount)
{
 return llAxisAngle2Rot(llRot2Axis(target/=source),amount*llRot2Angle(target))*source;
}
default
{
 state_entry()
 {
 swinging=0;
 open=FALSE;
 omega=TWO_PI/360*openingAngle/openingTime;
 llTargetOmega(ZERO_VECTOR,1.0,1.0);
 }
 touch_start(integer dummy)
 {
 go();
 }
 collision_start(integer dummy)
 {
 go();
 }
 timer()
 {
 if(swinging>0)
 {
 swinging--;
 if(swinging!=0)
 {
 float amount=(float) swinging/(float) steps;
 if(open)
 amount=1.0-amount;
 llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_ROT_LOCAL,slerp(closedRot,openRot,amount)]);
 return;
 }
 llTargetOmega(axis,0.0,0.0);
 if(open)
 {
 llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_ROT_LOCAL,openRot]);
 llSetTimerEvent(autocloseTime);
 }
 else
 {
 llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_ROT_LOCAL,closedRot]);
 sound(soundClose);
 llSetTimerEvent(0.0);
 }
 }
 else // autoclose time reached
 {
 llSetTimerEvent(0.0);
 openDoor(!open);
 swinging=steps;
 }
 }
}
==Changelog==
Version 1.2.1:
* Added a sound that plays when the door starts to close
Version 1.2:
* Now always aligns to the global coordinate system or root prim rotation, so you don't need two scripts anymore
* Added graceful sound handling
Version 1.1:
* Added rotation steps so people can start walking through the halfways-open door already
* Added opening on collision