User:Hidenori Glushenko/SmoothOpeningDoor

From Second Life Wiki
Jump to: navigation, search

DoorInit

<lsl> /**

*    door-init.lsl
*    Released into the public domain by Hidenori Glushenko
*/

default {

   state_entry() {
       list params = llGetPrimitiveParams([PRIM_TYPE]);
       params = llListReplaceList(params,[<0.125,0.625,0.0>],2,2);
       llSetPrimitiveParams([PRIM_TYPE]+params+[PRIM_SIZE,<1.6,2.0,0.05>]);
       llRemoveInventory(llGetScriptName());        
   }    

}</lsl>


SmoothOpeningDoor

<lsl> /*-------------------------------------------------------------------

*  Smooth opening door script
*  This door opens toward the directrion opposit to the avatar's pos.
*  Released into the public domain by Hidenori Glushenko
*-------------------------------------------------------------------
*  Please initialise your prim's share using door_init.lsl
*-------------------------------------------------------------------
*/

rotation DOOR_ROT_ORG; // base rotation float DOOR_DIV_EULER = 150.0; // open angle float DOOR_OPEN_SEC = 10.0; // open time(seconds) float DOOR_MOVE_TARGET; integer TIMER_COUNT; integer TIMER_MAX = 40; // open speed

                                               //  larger is slower

/**

*  @state  default state : initialize prim's status
*/

default {

   state_entry() {
       llSetBuoyancy(1.0);
       llMinEventDelay( 0.01 );
       llSetStatus(STATUS_PHANTOM, FALSE);
       llSetStatus(STATUS_BLOCK_GRAB, TRUE);
       state   DoorClose;
   }

}

/**

*  @state  closed state
*/

state DoorClose {

   touch_start(integer total_number) {
       DOOR_ROT_ORG = llGetRot();

       //  check the touched avatar's position
       vector av_offset = (llDetectedPos(0)-llGetPos())/DOOR_ROT_ORG;
       float av_offset_z = av_offset.z;

       //  calculate the angle depend on the avatar's pos
       DOOR_MOVE_TARGET = (av_offset_z/llFabs(av_offset_z))
                           *DOOR_DIV_EULER;
       state DoorOpen;
   }

}

/**

*  @state  opening-opened-closing state
*/

state DoorOpen {

   state_entry() {
       TIMER_COUNT = 0;
       llSetTimerEvent(0.05);
       llSetStatus(STATUS_PHANTOM, TRUE);          //  set phantom
   }
   
   state_exit() {
       llSetStatus(STATUS_PHANTOM, FALSE);         //  set non-phantom when leaving this state
       llSetTimerEvent(0.0);
   }

   touch_start(integer total_number) {
       //  restart timer
       llSetTimerEvent(0.05);
   }

   timer() {
       rotation rot;
       ++TIMER_COUNT;                              //  count up

       //  If counter indicates starting door-close
       if (TIMER_COUNT == TIMER_MAX + 1) {
           llSetStatus(STATUS_PHANTOM, TRUE);      //  set phantom
           llSetTimerEvent(0.05);
       }

       //  calculate door-angle from counter
       float x = PI_BY_TWO*TIMER_COUNT/(float)TIMER_MAX;   //  calculate x(means the ratio)
       float new_rot_euler = DOOR_MOVE_TARGET * llPow(llSin(x), 2.0);  //  calculate angle
       llRotLookAt(rot = (llEuler2Rot(<0.0,new_rot_euler,0.0>
           *DEG_TO_RAD))*DOOR_ROT_ORG,1.0,1.0);    //  set door angle

       //  stop when opened
       if (TIMER_COUNT == TIMER_MAX) {
           //  switch timer to the 'open-time'
           llSetTimerEvent(DOOR_OPEN_SEC);
           llSleep(0.2);
           llSetStatus(STATUS_PHANTOM, FALSE);     //  set non-phantom when opened
           llSetStatus(STATUS_PHYSICS, TRUE);      //  force update rotation
           llSetStatus(STATUS_PHYSICS, FALSE);     //  force update rotation
           llSetRot(rot);

       //  go to close state when closed
       } else if (TIMER_COUNT >= (TIMER_MAX*2)) {
           llSleep(0.2);
           llSetStatus(STATUS_PHYSICS, TRUE);      //  force update rotation
           llSetStatus(STATUS_PHYSICS, FALSE);     //  force update rotation
           llSetRot(DOOR_ROT_ORG);
           state DoorClose;            
       }
   }

}</lsl>