Difference between revisions of "Smooth Sliding Door"

From Second Life Wiki
Jump to navigation Jump to search
(Created page with '{{LSL Header}} Smooth Sliding Door Script ==Introduction== It really annoys me that there are so many bad looking doors out there that jerk around. While you can use llSetPos f...')
 
m (<lsl> tag to <source>)
 
(12 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{LSL Header}}
{{LSL Header}}
Smooth Sliding Door Script
=Smooth Sliding Door Script=


==Introduction==
==Introduction==
It really annoys me that there are so many bad looking doors out there that jerk around.  While you can use llSetPos for a sliding door you have no control at what speed it moves.  This sliding door script i created because i wanted to time my sliding door movements with the door sounds i had.  It uses llMoveToTarget to move the door, with the door temporally turning phantom as it moves.
It really annoys me that there are so many bad looking doors out there that jerk around.  While you can use llSetPos for a sliding door you have no control at what speed it moves.  This sliding door script i created because i wanted to time my sliding door movements with the door sounds i had.  It uses llMoveToTarget to move the door, with the door temporally turning phantom as it moves.


In laggy sims it will behave a little bit funky .. the door somtimes seeming to zoom off to the side as the door becomes a physical object. However, even with that defect it still looks much better IMHO
In laggy sims it will behave a little bit funky .. the door sometimes seeming to zoom off to the side before popping into the correct final position as the door becomes a physical object. However, even with that defect it still looks much better IMHO
 
===For a script with fewer problems, see "Alternative Script" at the end of this page.===
 


==The Script==
==The Script==


<lsl>
<source lang="lsl2">
// ********************************************************************
// ********************************************************************
//
//
Line 15: Line 18:
// by SimonT Quinnell  
// by SimonT Quinnell  
// 11/07/2009
// 11/07/2009
//
// If a notecard is in the prim it will be read as a configuration notecard
//
//
// NOTE: If you are going to reposition the door, do it while the door is closed.
// NOTE: If you are going to reposition the door, do it while the door is closed.
Line 23: Line 24:
// Licensed under the "OpenCollar License"
// Licensed under the "OpenCollar License"
// Ie. Licensed under the GPLv2, with the additional requirement that these scripts remain "full perms" in Second Life.
// Ie. Licensed under the GPLv2, with the additional requirement that these scripts remain "full perms" in Second Life.
//
// Edit: Simplified the script to be just a basic move script .. removed the sound triggers (5/1/2010)
//
//
// ********************************************************************
// ********************************************************************
Line 31: Line 34:
// ********************************************************************
// ********************************************************************


// NOTE: All of these constants can be set in the contained notecard
// Movement Constants
// Movement Constants
vector      OFFSET = <-2.0, 0.0, 0.0>;      // Directional offset for moving the door
vector      OFFSET = <-2.0, 0.0, 0.0>;      // Directional offset for moving the door in x,y,z coordinates
float      OPENTIME = 3.5;                // Time taken to open door
float      OPENTIME = 3.5;                // Time taken to open door
float      CLOSETIME = 3.5;                // Time taken to close door
float      CLOSETIME = 3.5;                // Time taken to close door
// Sound/volume to play on open and close, either a UUID or a name in the door contents
string      OPENSOUND = "";
float      OPENVOL = 1.0;
string      CLOSESOUND = "";
float      CLOSEVOL = 1.0;
// Misc. Constants
float      MAX_DISTANCE = 10.00;          // Maximum distance the touching avatar can be away
integer    DEBUG = FALSE;




Line 58: Line 49:
vector      vTargetPos;
vector      vTargetPos;
integer    bOpen = FALSE;
integer    bOpen = FALSE;
integer    bMoving = FALSE;


// internals for reading notecards
string      strNotecard;
integer    intLine1;
key        keyConfigQueryhandle;                 
key        keyConfigUUID;


// ********************************************************************
// ********************************************************************
// Functions
// Functions
// ********************************************************************
// ********************************************************************
debug(string debug)
{
    if (DEBUG) llWhisper(0,"DEBUG:"+llGetScriptName()+":"+debug);
}
string CropName(string name)
{// Crops avatar's name to first name
    return llDeleteSubString(name,llSubStringIndex(name," "),llStringLength(name) - 1);   
}
LoadNotecard()
{
    if (llGetInventoryNumber(INVENTORY_NOTECARD) > 0)
    {  // First notecard is used as the configuration notecard
        strNotecard = llGetInventoryName(INVENTORY_NOTECARD,0);
        keyConfigQueryhandle = llGetNotecardLine(strNotecard, intLine1 = 0);
        keyConfigUUID = llGetInventoryKey(strNotecard);
    }
    else llOwnerSay("Door Configuration Notecard is missing!");
CheckVariable(string token, string data)
    if (token == "offset") OFFSET = (vector)data;
    else if (token == "max_distance") MAX_DISTANCE = (float)data;
    else if (token == "open_time") OPENTIME = (float)data;
    else if (token == "close_time") CLOSETIME = (float)data;
    else if (token == "open_sound") OPENSOUND = data;
    else if (token == "open_volume") OPENVOL = (float)data;
    else if (token == "close_sound") CLOSESOUND = data;
    else if (token == "close_volume") CLOSEVOL = (float)data;
    else if (token == "debug") DEBUG = (integer)data;
}




Line 111: Line 61:
     if(!bOpen)
     if(!bOpen)
     {  // Initial conditions
     {  // Initial conditions
        bOpen = TRUE;               
         rRot = llGetRot();
         rRot = llGetRot();
         vPosition = llGetPos();
         vPosition = llGetPos();
Line 118: Line 69:
         vTargetPos = vPosition+OFFSET*rRot;
         vTargetPos = vPosition+OFFSET*rRot;
          
          
         // Set the timer to cleanup position .. nesessary for laggy sims
         // Set the timer to cleanup position
         llSetTimerEvent(OPENTIME);
         llSetTimerEvent(OPENTIME);      
       
        bOpen = TRUE;               
        if(OPENSOUND != "") llTriggerSound(OPENSOUND, OPENVOL);
     }else
     }else
     {         
     {         
        bOpen = FALSE;
         // Target Position
         // Target Position
         omega=CLOSETIME/llVecDist(<0,0,0>,OFFSET);
         omega=CLOSETIME/llVecDist(<0,0,0>,OFFSET);
         vTargetPos = vPosition;
         vTargetPos = vPosition;
          
          
         // Set the timer to cleanup position .. nesessary for laggy sims
         // Set the timer to cleanup position
         llSetTimerEvent(CLOSETIME);
         llSetTimerEvent(CLOSETIME);
        bOpen = FALSE;
        if(CLOSESOUND != "") llTriggerSound(CLOSESOUND, CLOSEVOL);                     
     }
     }
      
      
     // Set Door Physical and move it
     // Set Door Physical and move it
    bMoving = TRUE;
     llSetStatus(STATUS_PHANTOM, TRUE);
     llSetStatus(STATUS_PHANTOM, TRUE);
     llSetStatus(STATUS_PHYSICS, TRUE);
     llSetStatus(STATUS_PHYSICS, TRUE);
Line 146: Line 94:
{             
{             
     state_entry()
     state_entry()
    {  // Initial conditions
        rRot = llGetRot();
        vPosition = llGetPos();
    }   
       
    touch_start(integer num_detected)
     {
     {
         debug("STATE:default");
         MoveDoor();
         LoadNotecard();
    }
       
    timer()
    {
        // Clean up Position
        bMoving = FALSE;
        llSetTimerEvent(0.0);
        llSetStatus(STATUS_PHYSICS, FALSE);
        llSetStatus(STATUS_PHANTOM, FALSE);       
         llSetPrimitiveParams([ PRIM_POSITION, vTargetPos, PRIM_ROTATION, rRot ]);      
     }
     }
      
}</source>
     touch_start(integer num_detected)
 
     {
==The Script with Auto-Close==
         // Empty Touch State. Fixes problems with missing touch events
 
[[User:Flax Quirina|Flax Quirina]]: A minor off-spin of the script above would be to add an auto-close feature so that the door slides back after a certain user-defined period of time.
 
<source lang="lsl2">
// ********************************************************************
//
// Basic Physical Sliding Door Script
// by SimonT Quinnell (11/07/2009) edited by Flax Quirina
// for auto-close (17/06/2011).
//
// NOTE: If you are going to reposition the door, do it while the door is closed.
//  Otherwise it will try and use the old close position as a reference point.
//
// Licensed under the "OpenCollar License"
// Ie. Licensed under the GPLv2, with the additional requirement that these scripts remain "full perms" in Second Life.
//
// Edit: Simplified the script to be just a basic move script .. removed the sound triggers (5/1/2010)
//
// ********************************************************************
// ********************************************************************
// CONSTANTS
// ********************************************************************
// Movement Constants
vector      OFFSET = <-2.0, 0.0, 0.0>;      // Directional offset for moving the door in x,y,z coordinates
float      OPENTIME = 3.5;                // Time taken to open door
float      CLOSETIME = 3.5;                // Time taken to close door
float      AUTO_CLOSE_TIME = 5;              // Time to auto-close the door
// ********************************************************************
// Variables
// ********************************************************************
vector      vPosition;
rotation    rRot;
float      omega=0.0;
vector      vTargetPos;
integer    bOpen = FALSE;
integer    bMoving = FALSE;
integer    destTarget;
// ********************************************************************
// Functions
// ********************************************************************
MoveDoor()
{
     if(!bOpen)
     {  // Initial conditions
        bOpen = TRUE;               
        rRot = llGetRot();
        vPosition = llGetPos();
        // Target Position
        omega=OPENTIME/llVecDist(<0,0,0>,OFFSET);
        vTargetPos = vPosition+OFFSET*rRot;
        // Set the timer to cleanup position
        //llSetTimerEvent(OPENTIME);       
    }else
     {      
        bOpen = FALSE;
         // Target Position
        omega=CLOSETIME/llVecDist(<0,0,0>,OFFSET);
        vTargetPos = vPosition;
   
        // Set the timer to cleanup position
        //llSetTimerEvent(CLOSETIME);
     }
     }
    // Set Door Physical and move it
    bMoving = TRUE;
    llSetStatus(STATUS_PHANTOM, TRUE);
    llSetStatus(STATUS_PHYSICS, TRUE);
    destTarget = llTarget(vTargetPos, llVecDist(<0,0,0>,OFFSET));
    llMoveToTarget(vTargetPos,omega);
      
      
     dataserver(key keyQueryId, string strData)
}
     {
         if (keyQueryId == keyConfigQueryhandle)
         {
default
            if (strData != EOF)
{           
            {             
     state_entry()
                string strToken;
     {   // Initial conditions
                strData = llStringTrim(strData, STRING_TRIM_HEAD);    // Trim Whitespace
         rRot = llGetRot();
                if (llGetSubString (strData, 0, 0) != "#")        // is it a comment?
         vPosition = llGetPos();
                {
    }   
                    integer s = llSubStringIndex(strData, "=");
    at_target(integer tnum, vector targetpos, vector ourpos) {
                    if(~s)//does it have an "=" in it?
        if(llVecDist(targetpos, ourpos) < 0.1) {
                    {
            // Clean up Position
                        strToken = llToLower(llStringTrim(llDeleteSubString(strData, s, -1), STRING_TRIM));
            bMoving = FALSE;
                        strData = llStringTrim(llDeleteSubString(strData, 0, s), STRING_TRIM);
            llSetStatus(STATUS_PHYSICS, FALSE);
                        CheckVariable(strToken, strData);
            llSetStatus(STATUS_PHANTOM, FALSE);       
                    }
            llSetPrimitiveParams([ PRIM_POSITION, vTargetPos, PRIM_ROTATION, rRot ]);
                }
            llTargetRemove(destTarget);
                 keyConfigQueryhandle = llGetNotecardLine(strNotecard, ++intLine1);
            if(bOpen) {
                 llSetTimerEvent(AUTO_CLOSE_TIME);
             }
             }
            else
         }
            {
                llOwnerSay("Done Reading Config Notecard");
               
                state stopped;
            }
         }          
     }
     }
      
     touch_start(integer num_detected)
     changed(integer change)        
    {
        MoveDoor();
     }
    timer()
     {
     {
         if (change & CHANGED_INVENTORY)
         llSetTimerEvent(0.0);
         {
         MoveDoor();
            llResetScript();
        }
     }
     }
}
}
</source>


==Alternative Script==


state stopped
<source lang="lsl2">
// A go-Physical+Phantom Sliding Door by Omei Qunhua
// with Auto-computation of movement axis and distance
// To avoid problems, the script ignores touches while the door is moving
 
vector    gHome;                      // Position of the door in its initial closed position
rotation  gRot;                        // The initial rotation of the door prim
vector    gOffset;                    // This will be populated with the move distance stored in the appropriate axis position
integer    AUTO_CLOSE_TIME = 8;        // Can be zero if no auto-close is desired
 
StartMove(vector Target)
{
    // Set the door PHANTOM and PHYSICAL and start moving it
    llMoveToTarget(Target, 3);            // Do this first, to avoid the door dropping
    llSetStatus(STATUS_PHANTOM, TRUE);
    llSetStatus(STATUS_PHYSICS, TRUE);
    llSetTimerEvent(5);                    // Start a timer. We will end the move after this time.
}
EndMove(vector Target)
{
    // Return the door to non-phantom, non-physical and do a final confirmatory move
    llSetTimerEvent(0);
    llSetStatus(STATUS_PHYSICS, FALSE);
    llSetStatus(STATUS_PHANTOM, FALSE);
    llSetPrimitiveParams([ PRIM_POSITION, Target, PRIM_ROTATION, gRot ]);
}
 
default
{
{
     state_entry()
     state_entry()
     {
     {
         debug("STATE:stopped");
         gRot = llGetRot();
          
         gHome = llGetPos();
        vector Scale = llGetScale();
        // Find the middle sized dimension of the door prim
        // This determines the axis to move on, and the distance to move
        list lx = llListSort( [Scale.x, <1,0,0>, Scale.y, <0,1,0>, Scale.z, <0,0,1> ], 2, TRUE );
        gOffset = llList2Vector(lx, 3) * llList2Float(lx, 2);  // Apply the distance to move to the appropriate dimension
     }
     }
       
     touch_end(integer total_number)
     touch_start(integer num_detected)
     {
     {
         key        keyTouchingAvatar = llDetectedKey(0);
         state opening;
        float      distance = llVecDist(llGetPos(),llDetectedPos(0));
    }
}


        if (distance < MAX_DISTANCE)
state opening      // In this state, the door is in process of opening
        {
{
            state moving;
    state_entry()
        }
    {
         else llInstantMessage(keyTouchingAvatar, "You need to get a little closer to the door "+CropName(llKey2Name(keyTouchingAvatar)));
         StartMove(gHome + gOffset * gRot);
     }  
     }
      
     timer()
    changed(integer change)        
     {
     {
         if (change & CHANGED_INVENTORY && llGetInventoryNumber(INVENTORY_NOTECARD) > 0)
         EndMove(gHome + gOffset * gRot);
         {
         state open;
            state default;
     }
        }
     }  
}
}


state moving
state open        // The door is fully open
{
{
     state_entry()
     state_entry()
     {
     {
         debug("STATE:moving");
         llSetTimerEvent(AUTO_CLOSE_TIME);   // Close the door after this time (or not, if value is zero)
       
    }
        MoveDoor();
    // We will close the door either if it's touched while fully open, or after a time
    touch_end(integer num)
    {
        state closing;
     }
     }
      
     timer()
    state_exit()
     {
     {
         llSetTimerEvent(0.0);
         state closing;
     }  
     }
   
}
     touch_start(integer num_detected)
 
state closing        // State for when the door is in the process of closing
{
     state_entry()
     {
     {
         // Empty Touch State.  Fixes problems with missing touch events
         StartMove(gHome);
     }
     }
       
     timer()
     timer()
     {
     {
         // Clean up Position
         EndMove(gHome);
        llSetStatus(STATUS_PHYSICS, FALSE);
         state default;
        llSetStatus(STATUS_PHANTOM, FALSE);        
        llSetPrimitiveParams([ PRIM_POSITION, vTargetPos, PRIM_ROTATION, rRot ]);       
       
         state stopped;
     }
     }
}</lsl>
}
 
==Example Configuration Notecard==
 
<lsl># Configuration Notecard for Physical Door
 
# Touching
max_distance = 10.0
 
# Door Action Details
offset = <3.5,0.0,0.0>
open_time = 4.0
close_time = 4.0


# Door Sound Details
</source>
open_sound =
open_volume = 1.0
close_sound = 
close_volume = 1.0</lsl>


==See also==
==See also==
*[[ Script_Library | Script Library ]]
*[[ Script_Library | Script Library ]]
[[Category:LSL Library|Smooth Sliding Door Script]]

Latest revision as of 08:22, 25 January 2015

Smooth Sliding Door Script

Introduction

It really annoys me that there are so many bad looking doors out there that jerk around. While you can use llSetPos for a sliding door you have no control at what speed it moves. This sliding door script i created because i wanted to time my sliding door movements with the door sounds i had. It uses llMoveToTarget to move the door, with the door temporally turning phantom as it moves.

In laggy sims it will behave a little bit funky .. the door sometimes seeming to zoom off to the side before popping into the correct final position as the door becomes a physical object. However, even with that defect it still looks much better IMHO

For a script with fewer problems, see "Alternative Script" at the end of this page.

The Script

// ********************************************************************
//
// Basic Physical Sliding Door Script
// by SimonT Quinnell 
// 11/07/2009
//
// NOTE: If you are going to reposition the door, do it while the door is closed.
//  Otherwise it will try and use the old close position as a reference point.
//
// Licensed under the "OpenCollar License"
// Ie. Licensed under the GPLv2, with the additional requirement that these scripts remain "full perms" in Second Life.
//
// Edit: Simplified the script to be just a basic move script .. removed the sound triggers (5/1/2010)
//
// ********************************************************************


// ********************************************************************
// CONSTANTS
// ********************************************************************

// Movement Constants
vector      OFFSET = <-2.0, 0.0, 0.0>;      // Directional offset for moving the door in x,y,z coordinates
float       OPENTIME = 3.5;                 // Time taken to open door
float       CLOSETIME = 3.5;                // Time taken to close door


// ********************************************************************
// Variables
// ********************************************************************

vector      vPosition;
rotation    rRot;
float       omega=0.0;
vector      vTargetPos;
integer     bOpen = FALSE;
integer     bMoving = FALSE;


// ********************************************************************
// Functions
// ********************************************************************


MoveDoor()
{    
    if(!bOpen)
    {   // Initial conditions
        bOpen = TRUE;                
        rRot = llGetRot();
        vPosition = llGetPos();
        
        // Target Position
        omega=OPENTIME/llVecDist(<0,0,0>,OFFSET);
        vTargetPos = vPosition+OFFSET*rRot;
        
        // Set the timer to cleanup position
        llSetTimerEvent(OPENTIME);        
    }else
    {        
        bOpen = FALSE;

        // Target Position
        omega=CLOSETIME/llVecDist(<0,0,0>,OFFSET);
        vTargetPos = vPosition;
        
        // Set the timer to cleanup position
        llSetTimerEvent(CLOSETIME);
    }
    
    // Set Door Physical and move it
    bMoving = TRUE;
    llSetStatus(STATUS_PHANTOM, TRUE);
    llSetStatus(STATUS_PHYSICS, TRUE);
    llMoveToTarget(vTargetPos,omega);
}


default
{            
    state_entry()
    {   // Initial conditions
        rRot = llGetRot();
        vPosition = llGetPos();
    }    
        
    touch_start(integer num_detected)
    {
        MoveDoor();
    } 
        
    timer()
    {
        // Clean up Position
        bMoving = FALSE;
        llSetTimerEvent(0.0);
        llSetStatus(STATUS_PHYSICS, FALSE);
        llSetStatus(STATUS_PHANTOM, FALSE);         
        llSetPrimitiveParams([ PRIM_POSITION, vTargetPos, PRIM_ROTATION, rRot ]);        
    }
}

The Script with Auto-Close

Flax Quirina: A minor off-spin of the script above would be to add an auto-close feature so that the door slides back after a certain user-defined period of time.

// ********************************************************************
//
// Basic Physical Sliding Door Script
// by SimonT Quinnell (11/07/2009) edited by Flax Quirina
// for auto-close (17/06/2011).
//
// NOTE: If you are going to reposition the door, do it while the door is closed.
//  Otherwise it will try and use the old close position as a reference point.
//
// Licensed under the "OpenCollar License"
// Ie. Licensed under the GPLv2, with the additional requirement that these scripts remain "full perms" in Second Life.
//
// Edit: Simplified the script to be just a basic move script .. removed the sound triggers (5/1/2010)
//
// ********************************************************************
 
 
// ********************************************************************
// CONSTANTS
// ********************************************************************
 
// Movement Constants
vector      OFFSET = <-2.0, 0.0, 0.0>;      // Directional offset for moving the door in x,y,z coordinates
float       OPENTIME = 3.5;                 // Time taken to open door
float       CLOSETIME = 3.5;                // Time taken to close door
float       AUTO_CLOSE_TIME = 5;              // Time to auto-close the door
 
// ********************************************************************
// Variables
// ********************************************************************
 
vector      vPosition;
rotation    rRot;
float       omega=0.0;
vector      vTargetPos;
integer     bOpen = FALSE;
integer     bMoving = FALSE;
integer     destTarget;
 
// ********************************************************************
// Functions
// ********************************************************************
 
 
MoveDoor()
{
    if(!bOpen)
    {   // Initial conditions
        bOpen = TRUE;                
        rRot = llGetRot();
        vPosition = llGetPos();
 
        // Target Position
        omega=OPENTIME/llVecDist(<0,0,0>,OFFSET);
        vTargetPos = vPosition+OFFSET*rRot;
 
        // Set the timer to cleanup position
        //llSetTimerEvent(OPENTIME);        
    }else
    {        
        bOpen = FALSE;
 
        // Target Position
        omega=CLOSETIME/llVecDist(<0,0,0>,OFFSET);
        vTargetPos = vPosition;
 
        // Set the timer to cleanup position
        //llSetTimerEvent(CLOSETIME);
    }
 
    // Set Door Physical and move it
    bMoving = TRUE;
    llSetStatus(STATUS_PHANTOM, TRUE);
    llSetStatus(STATUS_PHYSICS, TRUE);
    destTarget = llTarget(vTargetPos, llVecDist(<0,0,0>,OFFSET));
    llMoveToTarget(vTargetPos,omega);
    
}
 
 
default
{            
    state_entry()
    {   // Initial conditions
        rRot = llGetRot();
        vPosition = llGetPos();
    }    
    at_target(integer tnum, vector targetpos, vector ourpos) {
        if(llVecDist(targetpos, ourpos) < 0.1) {
            // Clean up Position
            bMoving = FALSE;
            llSetStatus(STATUS_PHYSICS, FALSE);
            llSetStatus(STATUS_PHANTOM, FALSE);         
            llSetPrimitiveParams([ PRIM_POSITION, vTargetPos, PRIM_ROTATION, rRot ]);
            llTargetRemove(destTarget);
            if(bOpen) {
                llSetTimerEvent(AUTO_CLOSE_TIME);
            }
        }
    }
    touch_start(integer num_detected)
    {
        MoveDoor();
    } 
 
    timer()
    {
        llSetTimerEvent(0.0);
        MoveDoor();
    }
}

Alternative Script

// A go-Physical+Phantom Sliding Door by Omei Qunhua
// with Auto-computation of movement axis and distance
// To avoid problems, the script ignores touches while the door is moving

vector     gHome;                       // Position of the door in its initial closed position
rotation   gRot;                        // The initial rotation of the door prim
vector     gOffset;                     // This will be populated with the move distance stored in the appropriate axis position
integer    AUTO_CLOSE_TIME = 8;         // Can be zero if no auto-close is desired

StartMove(vector Target)
{
    // Set the door PHANTOM and PHYSICAL and start moving it
    llMoveToTarget(Target, 3);             // Do this first, to avoid the door dropping
    llSetStatus(STATUS_PHANTOM, TRUE);
    llSetStatus(STATUS_PHYSICS, TRUE);
    llSetTimerEvent(5);                    // Start a timer. We will end the move after this time.
}
EndMove(vector Target)
{
    // Return the door to non-phantom, non-physical and do a final confirmatory move
    llSetTimerEvent(0);
    llSetStatus(STATUS_PHYSICS, FALSE);
    llSetStatus(STATUS_PHANTOM, FALSE);
    llSetPrimitiveParams([ PRIM_POSITION, Target, PRIM_ROTATION, gRot ]);
}

default
{
    state_entry()
    {
        gRot = llGetRot();
        gHome = llGetPos();
        vector Scale = llGetScale();
        // Find the middle sized dimension of the door prim
        // This determines the axis to move on, and the distance to move
        list lx = llListSort( [Scale.x, <1,0,0>, Scale.y, <0,1,0>, Scale.z, <0,0,1> ], 2, TRUE ); 
        gOffset = llList2Vector(lx, 3) * llList2Float(lx, 2);  // Apply the distance to move to the appropriate dimension
    }
    touch_end(integer total_number)
    {
        state opening;
    }
}

state opening      // In this state, the door is in process of opening
{
    state_entry()
    {
        StartMove(gHome + gOffset * gRot);
    }
    timer()
    {
        EndMove(gHome + gOffset * gRot);
        state open;
    }
}

state open         // The door is fully open
{
    state_entry()
    {
        llSetTimerEvent(AUTO_CLOSE_TIME);    // Close the door after this time (or not, if value is zero)
    }
    // We will close the door either if it's touched while fully open, or after a time
    touch_end(integer num)
    {
        state closing;
    }
    timer()
    {
        state closing;
    }
}

state closing         // State for when the door is in the process of closing
{
    state_entry()
    {
        StartMove(gHome);
    }
    timer()
    {
        EndMove(gHome);
        state default;
    }
}

See also