Difference between revisions of "User:Kimm Paulino/Scripts"
Kimm Paulino (talk | contribs) |
Kimm Paulino (talk | contribs) (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>