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

From Second Life Wiki
Jump to navigation Jump to search
(Added my version of a path script)
Line 798: Line 798:
         llSetScale (size);
         llSetScale (size);
     }
     }
}
</lsl>
== Simple Path Script ==
<lsl>
// Path Setting Script
//
// In 'edit' mode, user moves the object and 'saves' various positions
// over time, then the positions can be replayed.  This either uses the physical
// move functions to create smooth movement or non-physical movements
// for a slightly more jerky movement!
//
// NOTE: Positions and rotations are relative to the region, so if you
// move the prim, then the positions won't move with it - you'd have to
// reset the script (using the 'reset' button) and store a new path.
//
// Depending on the settings, the system can either loop forever
// or play just once.
//
// It also has the option of resetting if you change owners, which
// might be useful if you want new owners to be able to store their
// own paths.
//
// Kimm Paulino
// Oct 2010
integer gDebug = FALSE;
integer gPhysics = FALSE; // Set to use physical movements
integer gLoop = TRUE; // Set to continually loop through the movements
integer gResetOnOwnerChange = TRUE; // Set if want script to auto reset when changing owners
list gPositionData; // Always assume that there are the same numbers
list gRotationData; // of position and rotation data points
integer gCurrentIdx;
float gTimePeriod = 2.0;
float gTau = 5.0;
key gOwnerId;
integer gListen;
integer gTimeHandle;
integer gTauHandle;
string gHelpMsg = "Use EDIT mode to move your object, selecting 'Save' to save each position.  Select 'Done' once complete.  Don't forget to save your first position too!";
string gErrorMsg = "Something unexpected went wrong, suggest you reset the script!";
string SAVE_BTN = "Save";
string DONE_BTN = "Done";
string TIME_BTN = "Time Adjust";
string TAU_BTN = "Tau Adjust";
string RESET_BTN = "Reset";
string START_BTN = "Start";
string STOP_BTN = "Stop";
string START_MSG = "start"; // What a passer by can type in via chat
integer LISTEN_CH = 600;
integer TIME_CH = 900;
integer TAU_CH = 901;
doDebug (string msg)
{
if (gDebug)
{
llOwnerSay (msg);
}
}
doMove()
{
    integer num_points = llGetListLength(gPositionData);
if (num_points != llGetListLength (gRotationData))
{
llOwnerSay (gErrorMsg);
disableMove();
return;
}
if (gCurrentIdx >= num_points)
{
if (gLoop)
{
// Loop around for another go
gCurrentIdx = 0;
}
else
{
// All complete
disableMove();
return;
}
}
doDebug ("Moving to position " + (string)gCurrentIdx);
    vector next_pos = llList2Vector (gPositionData, gCurrentIdx);
rotation next_rot = llList2Rot (gRotationData, gCurrentIdx);
   
    if (next_pos == ZERO_VECTOR && next_rot == ZERO_ROTATION)
    {
        // ignore
    }
else
{
if (gPhysics)
{
llMoveToTarget(next_pos, gTau);
llLookAt(next_pos,1,1);
llRotLookAt(next_rot,1,1);
}
else
{
// doDebug ("moving to: " + (string)next_pos);
llSetRot (next_rot);
llSetPos (next_pos);
}
}
// Move on to the next point
gCurrentIdx ++;
}
 
dialog ()
{
list buttons;
if (gPhysics)
{
buttons = [SAVE_BTN, DONE_BTN, RESET_BTN, START_BTN, STOP_BTN, TIME_BTN, TAU_BTN];
}
else
{
buttons = [SAVE_BTN, DONE_BTN, RESET_BTN, START_BTN, STOP_BTN, TIME_BTN];
}
    llDialog (gOwnerId, gHelpMsg, buttons, LISTEN_CH);
}
enableMove ()
{
if (gPhysics)
{
doDebug ("Enabling physical move");
llSetStatus (PRIM_PHYSICS, TRUE);
}
else
{
doDebug ("Enabling non-physical move");
llSetStatus(PRIM_PHYSICS, FALSE);
}
llSetTimerEvent (gTimePeriod);
gCurrentIdx = 0;
doMove ();
}
disableMove ()
{
doDebug ("Disabling move");
llSetStatus (PRIM_PHYSICS, FALSE);
llSetTimerEvent (0.0);
}
default
{
on_rez (integer start_param)
{
// if we reset on rez, then a user can't take an object into
// inventory have rerez it with the same path stored.
//
// Means that if they do want to clear the path, say because
// the position in the Sim has changed, then they have to use
// the 'reset' option.
}
state_entry()
llOwnerSay ("Ready to start saving positions.  Touch for menu, then go to SL Edit mode to move the object and use 'save' on the menu to save each position.");
gOwnerId = llGetOwner();
    }
   
touch_start(integer who)
{
gListen = llListen (LISTEN_CH,"",NULL_KEY,"");
if (llDetectedKey(0) == gOwnerId)
{
dialog();
}
else
{
if (!gLoop)
{
// Let nearby users start the moving
llWhisper  (0, "To start the movement, please type the following into local chat:  /" + (string)LISTEN_CH + " " + START_MSG);
}
}
    }
   
listen (integer channel, string name, key id, string msg)
{
vector pos = llGetPos();
rotation rot = llGetRot();
if (channel == LISTEN_CH)
{
if (msg == START_BTN || msg == START_MSG)
{
enableMove();
}
// non-owners can't do anything else
if (id != gOwnerId)
{
return;
}
if (msg == SAVE_BTN)
{
gPositionData += pos;
gRotationData += rot;
dialog ();
}
else if (msg == STOP_BTN)
{
disableMove();
}
else if (msg == RESET_BTN)
{
llResetScript();
}
else if (msg == TIME_BTN)
{
gTimeHandle = llListen (TIME_CH, "", gOwnerId, "");
llOwnerSay ("Adjust time using: /" + (string)TIME_CH + " <float seconds>");
}
else if (msg == TAU_BTN)
{
gTauHandle = llListen(TAU_CH, "", gOwnerId, "");
llOwnerSay ("Adjust Tau using: /" + (string)TAU_CH + " <float value>");
}
else if (msg == DONE_BTN)
{
llOwnerSay("To reset use: /" + (string)LISTEN_CH + " reset");
llOwnerSay("To start use: /" + (string)LISTEN_CH + " start");
}
}
if (channel == TIME_CH)
{
gTimePeriod = (float)msg;
llListenRemove (gTimeHandle);
llOwnerSay ("Time period set to " + msg);
}
if (channel == TAU_CH)
{
gTau = (float)msg;
llListenRemove (gTauHandle);
llOwnerSay ("Tau set to " + msg);
}
}
   
changed(integer ch)
{
if(ch & CHANGED_OWNER)
{
if (gResetOnOwnerChange)
{
// This will clear out all stored positions of course!
llResetScript();
}
}
}
timer()
{
doMove();
}
}
}
</lsl>
</lsl>

Revision as of 14:26, 5 October 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>

Prim Reducing Script

This will reduce a prim's size by scaling it by the specified number of steps and applying that scaling the specified number of times using a timer.

<lsl> // Reducing Script // // Kimm Paulino // Written for Stewart Bosatsu, Sept 2010

integer TIMER_STEPS = 18; float REDUCING_STEPS = 20; // If this >= TIMER_STEPS then prim will disappear float TIMER_INTERVAL = 2.0; // In seconds integer gCount; vector gReducingFactor;

default {

   on_rez (integer start_param)
   {
       llResetScript();
   }
   
   state_entry()
   {
       gCount = 0;
       vector size = llGetScale();
       float scaling = 1.0 / REDUCING_STEPS;
       gReducingFactor = size * scaling;
       
   }
   touch_start(integer total_number)
   {
       llSetTimerEvent (TIMER_INTERVAL);
   }
   
   timer ()
   {
       // Reduce the size by 1/TIMER_STEPS % each time
       gCount ++;
       if (gCount > TIMER_STEPS)
       {
           // disable and quit
           llSetTimerEvent (0.0);
           llDie();
           return;
       }
       
       // Reduce prim
       vector size = llGetScale();
       
       size = size - gReducingFactor;
       llSetScale (size);
   }

} </lsl>

Simple Path Script

<lsl> // Path Setting Script // // In 'edit' mode, user moves the object and 'saves' various positions // over time, then the positions can be replayed. This either uses the physical // move functions to create smooth movement or non-physical movements // for a slightly more jerky movement! // // NOTE: Positions and rotations are relative to the region, so if you // move the prim, then the positions won't move with it - you'd have to // reset the script (using the 'reset' button) and store a new path. // // Depending on the settings, the system can either loop forever // or play just once. // // It also has the option of resetting if you change owners, which // might be useful if you want new owners to be able to store their // own paths. // // Kimm Paulino // Oct 2010

integer gDebug = FALSE; integer gPhysics = FALSE; // Set to use physical movements integer gLoop = TRUE; // Set to continually loop through the movements integer gResetOnOwnerChange = TRUE; // Set if want script to auto reset when changing owners

list gPositionData; // Always assume that there are the same numbers list gRotationData; // of position and rotation data points integer gCurrentIdx; float gTimePeriod = 2.0; float gTau = 5.0; key gOwnerId; integer gListen; integer gTimeHandle; integer gTauHandle; string gHelpMsg = "Use EDIT mode to move your object, selecting 'Save' to save each position. Select 'Done' once complete. Don't forget to save your first position too!"; string gErrorMsg = "Something unexpected went wrong, suggest you reset the script!"; string SAVE_BTN = "Save"; string DONE_BTN = "Done"; string TIME_BTN = "Time Adjust"; string TAU_BTN = "Tau Adjust"; string RESET_BTN = "Reset"; string START_BTN = "Start"; string STOP_BTN = "Stop"; string START_MSG = "start"; // What a passer by can type in via chat integer LISTEN_CH = 600; integer TIME_CH = 900; integer TAU_CH = 901;

doDebug (string msg) { if (gDebug) { llOwnerSay (msg); } }

doMove() {

   integer num_points = llGetListLength(gPositionData); 

if (num_points != llGetListLength (gRotationData)) { llOwnerSay (gErrorMsg); disableMove(); return; }

if (gCurrentIdx >= num_points) { if (gLoop) { // Loop around for another go gCurrentIdx = 0; } else { // All complete disableMove(); return; } }

doDebug ("Moving to position " + (string)gCurrentIdx);

   vector next_pos = llList2Vector (gPositionData, gCurrentIdx);

rotation next_rot = llList2Rot (gRotationData, gCurrentIdx);

   if (next_pos == ZERO_VECTOR && next_rot == ZERO_ROTATION)
   {
       // ignore
   }

else { if (gPhysics) { llMoveToTarget(next_pos, gTau); llLookAt(next_pos,1,1); llRotLookAt(next_rot,1,1); } else { // doDebug ("moving to: " + (string)next_pos); llSetRot (next_rot); llSetPos (next_pos); } }

// Move on to the next point gCurrentIdx ++; }

dialog () { list buttons; if (gPhysics) { buttons = [SAVE_BTN, DONE_BTN, RESET_BTN, START_BTN, STOP_BTN, TIME_BTN, TAU_BTN]; } else { buttons = [SAVE_BTN, DONE_BTN, RESET_BTN, START_BTN, STOP_BTN, TIME_BTN]; }

   llDialog (gOwnerId, gHelpMsg, buttons, LISTEN_CH);

}

enableMove () { if (gPhysics) { doDebug ("Enabling physical move"); llSetStatus (PRIM_PHYSICS, TRUE); } else { doDebug ("Enabling non-physical move"); llSetStatus(PRIM_PHYSICS, FALSE); } llSetTimerEvent (gTimePeriod); gCurrentIdx = 0; doMove (); }

disableMove () { doDebug ("Disabling move"); llSetStatus (PRIM_PHYSICS, FALSE); llSetTimerEvent (0.0); }

default { on_rez (integer start_param) { // if we reset on rez, then a user can't take an object into // inventory have rerez it with the same path stored. // // Means that if they do want to clear the path, say because // the position in the Sim has changed, then they have to use // the 'reset' option. }

state_entry() { llOwnerSay ("Ready to start saving positions. Touch for menu, then go to SL Edit mode to move the object and use 'save' on the menu to save each position."); gOwnerId = llGetOwner();

   }
   

touch_start(integer who) { gListen = llListen (LISTEN_CH,"",NULL_KEY,""); if (llDetectedKey(0) == gOwnerId) { dialog(); } else { if (!gLoop) { // Let nearby users start the moving llWhisper (0, "To start the movement, please type the following into local chat: /" + (string)LISTEN_CH + " " + START_MSG); } }

   }
   

listen (integer channel, string name, key id, string msg) { vector pos = llGetPos(); rotation rot = llGetRot();

if (channel == LISTEN_CH) { if (msg == START_BTN || msg == START_MSG) { enableMove(); }

// non-owners can't do anything else if (id != gOwnerId) { return; }

if (msg == SAVE_BTN) { gPositionData += pos; gRotationData += rot; dialog (); } else if (msg == STOP_BTN) { disableMove(); } else if (msg == RESET_BTN) { llResetScript(); } else if (msg == TIME_BTN) { gTimeHandle = llListen (TIME_CH, "", gOwnerId, ""); llOwnerSay ("Adjust time using: /" + (string)TIME_CH + " <float seconds>"); } else if (msg == TAU_BTN) { gTauHandle = llListen(TAU_CH, "", gOwnerId, ""); llOwnerSay ("Adjust Tau using: /" + (string)TAU_CH + " <float value>"); } else if (msg == DONE_BTN) { llOwnerSay("To reset use: /" + (string)LISTEN_CH + " reset"); llOwnerSay("To start use: /" + (string)LISTEN_CH + " start"); } }

if (channel == TIME_CH) { gTimePeriod = (float)msg; llListenRemove (gTimeHandle); llOwnerSay ("Time period set to " + msg); }

if (channel == TAU_CH) { gTau = (float)msg; llListenRemove (gTauHandle); llOwnerSay ("Tau set to " + msg); } }

changed(integer ch) { if(ch & CHANGED_OWNER) { if (gResetOnOwnerChange) { // This will clear out all stored positions of course! llResetScript(); } } }

timer() { doMove(); } } </lsl>