Difference between revisions of "User:Kimm Paulino/Scripts"

From Second Life Wiki
Jump to navigation Jump to search
m (Added yet another door script ...)
(Added example of rotations in child prims)
Line 585: Line 585:
         llSetTimerEvent(0.0);            // Set the timer to 0.0 to turn it off
         llSetTimerEvent(0.0);            // Set the timer to 0.0 to turn it off
         state closed;                    // Move to the closed state
         state closed;                    // Move to the closed state
    }
}
</lsl>
== Child Prim Rotations ==
This is a test script to pull together all the advice about rotations about a centre of rotation, in local coordinates with the appropriate work arounds for setting rotations, etc.  Not really meant for use on its own (doesn't manage open/close state for example) but just to highlight the logic for applying the rotations.
<lsl>
// Testing child prim rotations.
// This is a script that could be used with a non-path-cut linked door or windows
// and so on, with the correct rotation offsets and calculations to function.
//
// Kimm Paulino, August 2010
// Specify the rotation to apply, as a Euler vector in degrees
vector gNewRotation_e = <0.0, 0.0, 150.0>;
// Specify the details of the Centre of Rotation to use.
// Can either work it out from the prim parameters or put a hardcoded one in here
integer gCorAxis = 1; // 1=x, 2=y, 3=z, -1=-x, -2=-y, -3=-z, 0=gCor
vector gCor = <0.0,0.0,0.0>; // Relative to root prim, if gCorAxis = 0
// This test script will automatically return the prim to its start
// parameters after this time.
float RESET_TIME = 5.0;
vector gInitialPosition;
rotation gInitialRotation;
store_child ()
{
llOwnerSay ("-----------------");
    gInitialPosition = llGetLocalPos();
llOwnerSay ("Initial Position: " + (string)gInitialPosition);
    gInitialRotation = llGetLocalRot();
llOwnerSay ("Initial Rotation: " + (string)r2v(gInitialRotation));
}
restore_child()
{
// Note: Use the PRIM_ROTATION workaround, as described in SVC-93
llSetPrimitiveParams ([ PRIM_POSITION, gInitialPosition,
PRIM_ROTATION, gInitialRotation / llGetRootRotation()]);
    //llSetPos (gInitialPosition);
    //llSetLocalRot (gInitialRotation);
}
vector calcCorAxis ()
{
// Note: If the prim is rotated, then we need to apply the
// same rotation to the size values to pick up the correct axis
vector prim_size = llGetScale() * llGetLocalRot();
if (gCorAxis == 1)
{
return <(prim_size.x/2.0), 0.0, 0.0>;
}
else if (gCorAxis == 2)
{
return <0.0, (prim_size.y/2.0), 0.0>;
}
else if (gCorAxis == 3)
{
return <0.0, 0.0, (prim_size.z/2.0)>;
}
else if (gCorAxis == -1)
{
return <(-prim_size.x/2.0), 0.0, 0.0>;
}
else if (gCorAxis == -2)
{
return <0.0, (-prim_size.y/2.0), 0.0>;
}
else if (gCorAxis == -3)
{
return <0.0, 0.0, (-prim_size.z/2.0)>;
}
else
{
return gCor;
}
}
vector r2v (rotation r)
{
return (RAD_TO_DEG * llRot2Euler (r));
}
// rot is a rotation to be applied to the prim
// cor is a relative position (to the root) for the centre of rotation
rotate_child (rotation rot, vector cor)
{
// Work in local coordinates
    vector current_position = llGetLocalPos();
    rotation current_orientation = llGetLocalRot();
llOwnerSay ("Current position/rotation: " + (string)current_position + " / " + (string)r2v(current_orientation));
    // Calculate the offset from the centre of the object
    // to the centre of rotation.  This effectively moves
    // the object so that the cor can be thought off as the
    // origin.  Once we've done the calculations, we'll move it back.
    vector normalised_position = current_position - cor;
llOwnerSay ("Normalised position/COR: " + (string)normalised_position + " / " + (string)cor);
   
    // Calculate the new position by applying the required
    // rotation to the current position (i.e. rotate the
    // vector origin-position to produce origin-newposition)
    vector new_normalised_position = normalised_position * rot;
llOwnerSay ("Rotated Normalised Position: " + (string)new_normalised_position);
    vector new_position = cor + new_normalised_position;
llOwnerSay ("New Actual Position: " + (string)new_position);
   
    rotation new_orientation = current_orientation * rot;
llOwnerSay ("New Orientation: " + (string)r2v(new_orientation));
   
    // Set local position and rotation
    // Note: There is no llSetLocalPos - llSetPos will do local coords for a child
    //llSetPos (new_position);
    //llSetLocalRot (new_orientation);
// However, use llSetPrimitiveParams to set both at same time, without
// incurring two 0.2s delays ... although note, have to use
// the PRIM_ROTATION workaround, as described in SVC-93
llSetPrimitiveParams ([ PRIM_POSITION, new_position,
PRIM_ROTATION, new_orientation / llGetRootRotation()]);
}
default
{
    on_rez (integer start_param)
    {
        llResetScript();
    }
    state_entry ()
    {
        // store initial position/etc
        store_child ();
    }
   
    touch_start (integer num_detected)
    {
// Need to convert CoR to local coordinates relative to
// the root prim (not just relative to this prim).
vector cor = llGetLocalPos() + calcCorAxis();
        rotate_child (llEuler2Rot (gNewRotation_e * DEG_TO_RAD), cor);
        llSetTimerEvent (RESET_TIME);
    }
   
    timer ()
    {
        restore_child ();
        llSetTimerEvent (0.0);
     }
     }
}
}
</lsl>
</lsl>

Revision as of 16:12, 3 September 2010

Simple Teleport

<lsl> // Teleports on 'left click' (touch). // // Set the coordinates to tp to in the DEST= line after these comments. // // Kimm Paulino // Sept 2009 // // Teleport bit based on the following: // // Copyright (c) 2008, Scripting Your World // All rights reserved. // // Scripting Your World // By Dana Moore, Michael Thome, and Dr. Karen Zita Haigh // http://syw.fabulo.us // http://www.amazon.com/Scripting-Your-World-Official-Second/dp/0470339837/ // // You are permitted to use, share, and adapt this code under the // terms of the Creative Commons Public License described in full // at http://creativecommons.org/licenses/by/3.0/legalcode. // That means you must keep the credits, do nothing to damage our // reputation, and do not suggest that we endorse you or your work. // // Listing 2.4: Teleport3 - Optimized Intrasim Teleport

vector DEST = <224, 213, 22>; // the teleport will be to this location vector SITPOS = <0,0,0.5>; key gAv;

moveTo(vector origin, vector destination ) { // removed jumpdist

   float dist = llVecDist(origin, destination);
   integer passes = llCeil( llLog(dist/10.0) / llLog(2.0) );
   integer i;
   list params = [PRIM_POSITION, destination];
   for (i=0; i<passes; i++) {
       params = (params=[]) + params + params;
   }
   llSetPrimitiveParams(params);

}

teleport(key av) {

   if (av == NULL_KEY)
   {
       return;
   }
   vector origin = llGetPos();
   llSetAlpha (0.0, ALL_SIDES);
   moveTo(origin, DEST);
   // no need to sleep -- llSetPrimParams has 0.2s delay
   llUnSit(av);
   moveTo(DEST, origin);
   llSetAlpha (1.0, ALL_SIDES);

}

default {

   state_entry()
   {
       llSetClickAction (CLICK_ACTION_SIT);
       llSitTarget(SITPOS, ZERO_ROTATION);
   }
   changed(integer changebits)
   {
       if (changebits & CHANGED_LINK)
       {
           gAv = llAvatarOnSitTarget();
           if (gAv != NULL_KEY)
           {
               teleport(gAv);
           }
       }
   }

} </lsl>

Die after 10 minutes

<lsl> // This will kill the prim it is in, 10 minutes after the prim has been rezzed. // // Kimm Paulino, June 2010

default {

   state_entry()
   {
       // 10 minutes
       llSetTimerEvent (600.0);
   }
   
   timer ()
   {
       llSetTimerEvent (0.0);
       llDie();
   }

} </lsl>


Simple Prim Texture Changer

<lsl> // Texture changer. Will cycle through all textures // in the prims inventory. // // Kimm Paulino // Written for Bebelou Naidoo, April 2010

float TIMER_PERIOD = 5.0; // in seconds. integer RANDOM = 1; // 0 = sequential, 1 = random

// globals integer gNumTextures; integer gLastTexture;

default {

   on_rez (integer n)
   {
       llResetScript();
   }
   state_entry()
   {
       gLastTexture = 0;
       gNumTextures = llGetInventoryNumber(INVENTORY_TEXTURE);
       llSetTimerEvent(TIMER_PERIOD);
   }
   
   timer()
   {
       integer nextTexture;
       if (RANDOM)
       {
           // Randomly choose one
           nextTexture = (integer)llFrand (gNumTextures);
       }
       else
       {
           // Move on from the last one
           gLastTexture ++;
           if (gLastTexture > gNumTextures)
           {
               gLastTexture = 0;
           }
           nextTexture = gLastTexture;
       }
       string texture = llGetInventoryName(INVENTORY_TEXTURE, nextTexture);
       llSetTexture(texture, ALL_SIDES);
   }

} </lsl>

Phantom Prim Setter

<lsl> // Script to make a prim appear to be phantom, so it can be linked, etc, // without actually being phantom. // // Basic technique found on the SL forums (sorry, I can't remember where). // // Kimm Paulino // Written for Synonyme Toll, May 2010

default {

   on_rez (integer start_param)
   {
       llResetScript();
   }
   
   state_entry()
   {
       // This makes the prim appear to be 'phantom like' without
       // actually making it phantom ...
       llVolumeDetect(TRUE);
       
       // Now disable the script once we've done our job
       llSetScriptState(llGetScriptName(), FALSE);
   }

} </lsl>

Floating Script

<lsl> // Script for applying a small, random impulse to physical objects // to make them float about. // // Note: There is no bound to where the objects go, this script // is meant for objects in a physically bounded area (like a fish tank with a lid) // // Feel free to use as you wish, but do let me know if you find something // interesting to do with it ... // // Kimm Paulino // Written for Synonyme Toll, Sept 2009 //

// How often to apply the new impulse (in seconds) float IMPULSE_TIME = 3.0;

// Range for the magnitude and x, y, z directions of the impulse float IMPULSE_RANGE = 0.5;

float newRand (float range) {

   // Want a random number in range +- 'range'
   return (llFrand(range) - (range/2.0));

}

applySmallImpulse () {

   vector my_vec = llGetVel();
   float  my_mag = llVecMag (my_vec);
   vector my_dir = llVecNorm (my_vec);
   // Change the magnitude slightly ...
   my_mag = my_mag + newRand(IMPULSE_RANGE);
   
   // Change the direction slightly too ...
   my_dir = <my_dir.x + newRand(IMPULSE_RANGE), my_dir.y + newRand(IMPULSE_RANGE), my_dir.z + newRand(IMPULSE_RANGE)>;
   
   vector new_vec = my_dir * my_mag;
   
   //llOwnerSay ("Applying Impulse: " + (string)new_vec);
   // apply the impulse to us
   llApplyImpulse (new_vec, TRUE);

}

default {

   on_rez(integer n)
   {
       llResetScript ();
   }
   
   state_entry()
   {
       // Turn on Physics
       llSetPrimitiveParams ([PRIM_PHYSICS, TRUE]);
       
       // Set the boyancy to > 1.0 so that it floats
       llSetBuoyancy (1.0);
       
       // Set up a timer to apply an impulse
       llSetTimerEvent (IMPULSE_TIME);
   }
   
   timer()
   {
       applySmallImpulse();
   }

} </lsl>

Sit and Play Animation

<lsl> // Sets a sit target and plays whatever animation is // stored in the contents on the prim when someone sits down. // // Kimm Paulino // Written for Synonyme Toll, April 2010

// These numbers are totally dependent on the object containing // the script, and possibly even the animation to be used too. vector gPosition = <0.0, 0.0, 0.1>; vector gRotation = <0.0, 0.0, 0.0>; // in degrees

default {

   on_rez (integer start_param)
   {
       llResetScript();
   }
   
   state_entry()
   {
       // These numbers are totally dependent on the object containing the script!
       llSitTarget (gPosition, llEuler2Rot (gRotation * DEG_TO_RAD));
   }
   changed (integer change)
   {
       // When someone sits on an object, the av is considered to be
       // a linked-in child prim, so the link number changes
       if (change & CHANGED_LINK)
       {
           key av = llAvatarOnSitTarget();
           if (av)
           {
               // yes so need to play the animation
               // first request permissions - results in the callback ...
               llRequestPermissions(av, PERMISSION_TRIGGER_ANIMATION);
           }
       }
   }
   
   run_time_permissions(integer perms)
   {
       // Do we have permissions to run the animations?
       // results in the timer!
       if(perms)
       {
           llSetTimerEvent(1.0);
       }
       else
       {
           llSetTimerEvent(0.0);
       }
   }
   
   timer()
   {
       key av = llAvatarOnSitTarget();
       // If the av is still sitting, play the animation stored in the prim
       if (av)
       {
           llStopAnimation("sit");
           llStartAnimation( llGetInventoryName( INVENTORY_ANIMATION, 0 ));
       }
       else
       {
           // stop playing the animations for sitting if the av
           // is no longer sitting ...
           llStopAnimation("sit_generic");
       }
   }

} </lsl>

Move up and down

<lsl> // Makes an object go up or down, gradually, when touched. // In order to make it a gradual movement, it uses a physical // object, which means it might be a little wobbly ... // // Kimm Paulino // Written for Nicollette Arabello, November 2009 //

integer gState; integer DOWN=0; integer GO_UP=1; integer UP=2; integer GO_DOWN=3;

float MOVE_DAMPING=4.0; float MOVE_TIME=4.0;

// Move to 1m above starting position vector gOffset = <0.0, 0.0, 1.0>; vector gStartPosition;

default {

   state_entry()
   {
       // Use physics so that can use MoveToTarget
       gStartPosition = llGetPos ();
       
       // Stop the object rotating
       llSetStatus(STATUS_ROTATE_X|STATUS_ROTATE_Y|STATUS_ROTATE_Z, FALSE);
       llSetStatus(STATUS_PHYSICS, TRUE);
       llMoveToTarget (gStartPosition, MOVE_DAMPING);
       llSetTimerEvent (MOVE_TIME);
   }
   
   on_rez(integer n)
   {
       llResetScript();
   }
   timer ()
   {
       if (gState == DOWN)
       {
           gState = GO_UP;
           llMoveToTarget(gStartPosition + gOffset, MOVE_DAMPING);
           gState = UP;
       }
       else if (gState == UP)
       {
           gState = GO_DOWN;
           llMoveToTarget(gStartPosition, MOVE_DAMPING);
           gState = DOWN;
       }
   }

} </lsl>

Simple Door

<lsl> // Was asked to modify an existing door script. I was just given // this to update so afraid I can't give credit, but if you know where // the original came from, do let me know. // // Swinging door LSL script #1 // Handles the touch event. // Handles the collision event. // Handles closing the door automatically via a timer event. // Triggers sounds when the door opens or closes. // // Updated by Kimm Paulino, April 2010, for Synonyme Toll, // to use local coords for the rotations instead of global // coords. // // Updated by Kimm Paulino, May 2010, for Synonyme Toll, // to use messages to link two doors together. // // Note: For this to work, you need a door with a path cut // of 0.375 to 0.875 and a width that is twice as wide // as you need (the cut brings it back down to the right // size). Without this, it will just rotate on the spot, // not swing at the edge. //

// Parameters you might want to change

float delay = 3.0; // time to wait before automatically closing door

                               // set to 0.0 to not automatically close

float direction = 1.0; // set to 1.0 or -1.0 to control direction the door swings float volume = 0.5; // 0.0 is off, 1.0 is loudest integer linked_doors = 0; // set to 1 if using this script in a linked set of doors float angle = 90.0; // angle to open in degrees integer coll_detect = 1; // set to 1 to make door open on approach

// Variables you will most likely leave the same

key open_sound = "cb340647-9680-dd5e-49c0-86edfa01b3ac"; key close_sound = "e7ff1054-003d-d134-66be-207573f2b535";

// KP: Link send/recv functions // IMPORTANT // If you only have one pair of doors using this script, then // these will be fine. If you have several doors using this // script that you don't want all opening together, then // you'll have to change these to something unique. // integer LINK_MSG_NUM = 452345; string LINK_MSG_STR_OPEN = "Open the door"; string LINK_MSG_STR_CLOSE = "Close the door";

linkSend (string dir) {

   if (linked_doors)
   {
       // Note: Could try to work out the link numbers of the doors,
       // but simplest is to send to all other prims in the build.
       llMessageLinked (LINK_ALL_OTHERS, LINK_MSG_NUM, dir, NULL_KEY);
   }

}

integer linkRecv (integer sender_num, integer num, string str, key id, string str_to_check) {

   if (linked_doors)
   {
       // Check it really is a message for these doors
       if (num == LINK_MSG_NUM)
       {
           if (str == str_to_check)
           {
               // All good
               return 1;
           }
       }
   }
   
   // not for us
   return 0;

}

// Processing for the script when it first starts up

default {

   // What we do when we first enter this state
   state_entry() {
       state open;                        // Move to the open state
   }

}

// Processing for the script when it is in the closed state

state closed {

   // What we do when we first enter this state
   state_entry() {
       llTriggerSound(close_sound, volume); // Trigger the sound of the door closing
       llSetLocalRot(llEuler2Rot(<0, 0, direction * angle * DEG_TO_RAD>) * llGetLocalRot());
   }
   // What we do when the door is clicked (”touched”) with the mouse
   touch_start(integer total_number) {
       linkSend (LINK_MSG_STR_OPEN);  // KP: Tell everyone else we are now in the open state
       state open;                        // Move to the open state
   }
   // What to do when something hits the door 
   collision_start(integer total_number)
   {
       if (coll_detect != 0)
       {
           linkSend (LINK_MSG_STR_OPEN);  // KP: Tell everyone else we are now in the open state
           state open;                        // Move to the open state
       }
   }
   
   // KP: Handle link messages
   
   link_message (integer sender_num, integer num, string str, key id)
   {
       if (linkRecv (sender_num, num, str, id, LINK_MSG_STR_OPEN))
       {
           state open;                    // Move to the open state
       }
   }
   // What to do when the timer goes off
   timer()
   {
       llSetTimerEvent(0.0);              // Set the timer to 0.0 to turn it off
   }

}

// Processing for the script when it is in the open state

state open {

   // What we do when we first enter this state
   state_entry() {
       llTriggerSound(open_sound, volume);// Trigger the sound of the door opening
       llSetLocalRot(llEuler2Rot(<0, 0, -direction * angle * DEG_TO_RAD>) * llGetLocalRot());
       llSetTimerEvent(delay);            // Set the timer to automatically close it
   }
   // What do do when pulling the door from Inventory if it was saved while open
   on_rez(integer start_param) {
       state closed;
   }
   // What we do when the door is clicked (”touched”) with the mouse
   touch_start(integer total_number) {
       linkSend (LINK_MSG_STR_CLOSE);  // KP: Tell everyone else we are now in the open state
       state closed;                      // Move to the closed state
   }
   // What to do when something hits the door 
   collision_start(integer total_number)
   {
       // Do nothing, the door is already open
   }
   // KP: Handle link messages
   
   link_message (integer sender_num, integer num, string str, key id)
   {
       if (linkRecv (sender_num, num, str, id, LINK_MSG_STR_CLOSE))
       {
           state closed;                    // Move to the open state
       }
   }
   // What to do when the timer goes off
   timer()
   {
       llSetTimerEvent(0.0);             // Set the timer to 0.0 to turn it off
       state closed;                     // Move to the closed state
   }

} </lsl>

Child Prim Rotations

This is a test script to pull together all the advice about rotations about a centre of rotation, in local coordinates with the appropriate work arounds for setting rotations, etc. Not really meant for use on its own (doesn't manage open/close state for example) but just to highlight the logic for applying the rotations.

<lsl> // Testing child prim rotations. // This is a script that could be used with a non-path-cut linked door or windows // and so on, with the correct rotation offsets and calculations to function. // // Kimm Paulino, August 2010

// Specify the rotation to apply, as a Euler vector in degrees vector gNewRotation_e = <0.0, 0.0, 150.0>;

// Specify the details of the Centre of Rotation to use. // Can either work it out from the prim parameters or put a hardcoded one in here integer gCorAxis = 1; // 1=x, 2=y, 3=z, -1=-x, -2=-y, -3=-z, 0=gCor vector gCor = <0.0,0.0,0.0>; // Relative to root prim, if gCorAxis = 0

// This test script will automatically return the prim to its start // parameters after this time. float RESET_TIME = 5.0;

vector gInitialPosition; rotation gInitialRotation;

store_child () { llOwnerSay ("-----------------");

   gInitialPosition = llGetLocalPos();

llOwnerSay ("Initial Position: " + (string)gInitialPosition);

   gInitialRotation = llGetLocalRot();

llOwnerSay ("Initial Rotation: " + (string)r2v(gInitialRotation)); }

restore_child() { // Note: Use the PRIM_ROTATION workaround, as described in SVC-93 llSetPrimitiveParams ([ PRIM_POSITION, gInitialPosition, PRIM_ROTATION, gInitialRotation / llGetRootRotation()]);

   //llSetPos (gInitialPosition);
   //llSetLocalRot (gInitialRotation);

}

vector calcCorAxis () { // Note: If the prim is rotated, then we need to apply the // same rotation to the size values to pick up the correct axis vector prim_size = llGetScale() * llGetLocalRot(); if (gCorAxis == 1) { return <(prim_size.x/2.0), 0.0, 0.0>; } else if (gCorAxis == 2) { return <0.0, (prim_size.y/2.0), 0.0>; } else if (gCorAxis == 3) { return <0.0, 0.0, (prim_size.z/2.0)>; } else if (gCorAxis == -1) { return <(-prim_size.x/2.0), 0.0, 0.0>; } else if (gCorAxis == -2) { return <0.0, (-prim_size.y/2.0), 0.0>; } else if (gCorAxis == -3) { return <0.0, 0.0, (-prim_size.z/2.0)>; } else { return gCor; } }

vector r2v (rotation r) { return (RAD_TO_DEG * llRot2Euler (r)); }

// rot is a rotation to be applied to the prim // cor is a relative position (to the root) for the centre of rotation rotate_child (rotation rot, vector cor) { // Work in local coordinates

   vector current_position = llGetLocalPos();
   rotation current_orientation = llGetLocalRot();

llOwnerSay ("Current position/rotation: " + (string)current_position + " / " + (string)r2v(current_orientation));

   // Calculate the offset from the centre of the object
   // to the centre of rotation.  This effectively moves
   // the object so that the cor can be thought off as the
   // origin.  Once we've done the calculations, we'll move it back.
   vector normalised_position = current_position - cor;

llOwnerSay ("Normalised position/COR: " + (string)normalised_position + " / " + (string)cor);

   // Calculate the new position by applying the required
   // rotation to the current position (i.e. rotate the
   // vector origin-position to produce origin-newposition)
   vector new_normalised_position = normalised_position * rot;

llOwnerSay ("Rotated Normalised Position: " + (string)new_normalised_position);

   vector new_position = cor + new_normalised_position;

llOwnerSay ("New Actual Position: " + (string)new_position);

   rotation new_orientation = current_orientation * rot;

llOwnerSay ("New Orientation: " + (string)r2v(new_orientation));

   // Set local position and rotation
   // Note: There is no llSetLocalPos - llSetPos will do local coords for a child
   //llSetPos (new_position);
   //llSetLocalRot (new_orientation);

// However, use llSetPrimitiveParams to set both at same time, without // incurring two 0.2s delays ... although note, have to use // the PRIM_ROTATION workaround, as described in SVC-93 llSetPrimitiveParams ([ PRIM_POSITION, new_position, PRIM_ROTATION, new_orientation / llGetRootRotation()]);

}

default {

   on_rez (integer start_param)
   {
       llResetScript();
   }
   state_entry ()
   {
       // store initial position/etc
       store_child ();
   }
   
   touch_start (integer num_detected)
   {

// Need to convert CoR to local coordinates relative to // the root prim (not just relative to this prim). vector cor = llGetLocalPos() + calcCorAxis();

       rotate_child (llEuler2Rot (gNewRotation_e * DEG_TO_RAD), cor);
       llSetTimerEvent (RESET_TIME);
   }
   
   timer ()
   {
       restore_child ();
       llSetTimerEvent (0.0);
   }

} </lsl>