// 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 + ""); } else if (msg == TAU_BTN) { gTauHandle = llListen(TAU_CH, "", gOwnerId, ""); llOwnerSay ("Adjust Tau using: /" + (string)TAU_CH + " "); } 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(); } }