// Mouselook Mover v2 by Moriash Moreau // March, 2007 // This script will allow the user to fly in any direction he looks while // in Mouselook, and hold his position when stationary. Speed is adjustable. // Use this script for whatever purpose you like, provided it is legal // and obeys the Second Life Terms of Service. // Instructions: // 1. Make a prim and drop this script into it. // 2. Attach the prim to any convenient location. HUD locations are // probably the most convenient. // 3. To use, enter Mouselook and press the left mouse button to move. // // Position will be held when the mouse button is released, in order // to prevent drift at high altitudes. Press the back arrow to release. // Touch the object to adjust movement speed. // WARNING! // Annoying SL bug. If you edit a script in an attachment that causes physical movement or force, // (such as one that uses llMoveToTarget, llPushObject, llSetForce, or llApplyImpulse), it will // not apply the force until the object is detached and re-attached. Keep that in mind // when working with this script. // Maximum speed multiplier. See ShowSpeed comment below. integer MaxSpeed = 20; // Tick is the time between movement calls. Damping is the damping time for the MoveToTarget. // Generally, Tick should be less than damping for smoother movement. Vary these numbers // to taste. Lower Damping will result in overall faster movement, as will lower Tick. // As Tick and Damping get closer together, movement becomes more jerky. Vary these parameters // experimentally. Tick of 0.2 and Damping of 0.5 seems to work reasonably well. float Tick = 0.2; float Damping = 0.5; // INTERNAL VARIABLES; integer Speed = 10; // Initial speed integer have_permissions = FALSE; integer Listener; integer CommChannel; integer CommListen; integer Locked; // Move in the direction we're currently looking. Move() { llMoveToTarget(llGetPos() + llRot2Fwd(llGetRot()) * Speed,Damping); } // Bring up the speed control dialog box. Pick a random channel each time. // Listen to menu responses. BaseMenu() { llListenRemove(CommListen); // Clear up old listen, in case "ignore" was selected last time. CommChannel = (integer)(llFrand(2400000) + 1); // Swap channels to prevent spurious dialogs. CommListen = llListen(CommChannel,"",llGetOwner(),""); // Listen to the channel. llDialog(llGetOwner(),"Current Speed = " + (string)Speed, ["Increase", "Decrease","Unlock","Close Menu","Disable"],CommChannel); // Send dialog on the channel. } // Display the current speed setting. Speed is a relative multiplier, not an absolute m/s. // One could adjust the movement and timer delays to approximate meters // per second, but it's kind of tricky with damped llMoveToTarget movement, // as it doesn't move at a constant speed. ShowSpeed() { llSetText("Speed: " + (string)Speed,<1,1,1>,1.0); } Init() { llStopMoveToTarget(); // Safety measure to keep from being flung across the sim // if there's an old move in place from last detach/edit. Locked = FALSE; llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS); } default { state_entry() { llSetColor(<0,0,0>,ALL_SIDES); llSetText("",<1,1,1>,1.0); } on_rez(integer param) { llOwnerSay("Touch to enable Mouse Mover."); } touch_start(integer param) { state Active; } } state Active { state_entry() { llSetColor(<1,1,1>,ALL_SIDES); ShowSpeed(); Init(); } // If we have permission, monitor the Mouselook Mouse Button, listen to "/1 unlock", // reset the color. run_time_permissions(integer permissions) { if (permissions == PERMISSION_TAKE_CONTROLS) { llTakeControls(CONTROL_ML_LBUTTON, TRUE, FALSE); have_permissions = TRUE; ShowSpeed(); llListenRemove(Listener); Listener = llListen(1, "", llGetOwner() , "unlock" ); llSetColor(<1,1,1>,ALL_SIDES); llOwnerSay("Enter Mouselook and hold down the left mouse button to move. Touch this object to adjust speed. Select \"Unlock\" from the touch menu or say \"/1 unlock\" to return to free movement. This device is best used while flying."); } } // On attachment, ask for permission to take controls. // On detach, release controls and stop movement. attach(key attachedAgent) { if (attachedAgent != NULL_KEY) { state default; } else { llStopMoveToTarget(); if (have_permissions) { llReleaseControls(); } } } // Bring up the dialog on touch. touch_start(integer param) { BaseMenu(); } // Interpret the dialog box. Keep bringing it up again until Ignore or Quit pressed. listen(integer channel, string name, key id, string message) { llListenRemove(CommListen); // Stop bringing up the dialog box. if (message == "Close Menu") { return; } else if (message == "Disable") { llOwnerSay("Disabling Mouselook Mover."); llStopMoveToTarget(); if (have_permissions) { llReleaseControls(); } state default; } // If "unlock" is sent via dialog box or on channel 1, stop holding our position // and set to off color. Don't bring up another box. else if (llToLower(message) == "unlock") { if (Locked) { llOwnerSay("Releasing."); llSetTimerEvent(0); llStopMoveToTarget(); Locked = FALSE; llSetColor(<1,1,1>,ALL_SIDES); return; } // If we're already unlocked, notify. Bring up menu. else { llOwnerSay("Already unlocked."); } } // Increase the speed, up to the max. else if (message == "Increase") { if (Speed < MaxSpeed) { Speed = Speed + 1; ShowSpeed(); } else { llOwnerSay("Speed is maxed out."); } } // Decrease speed, down to speed 1. else if (message == "Decrease") { if (Speed > 1) { Speed = Speed - 1; ShowSpeed(); } else { llOwnerSay("Already at minimum speed."); } } // Bring up the dialog box again each listen until "quit" or "ignore" is selected. BaseMenu(); } // Interpret keypresses. control(key name, integer held, integer change) { // If we press and hold the mouse button in Mouselook, run the timer. if (held & change & CONTROL_ML_LBUTTON) { Locked = TRUE; llSetTimerEvent(Tick); llSetColor(<0,1,0>,ALL_SIDES); } // If we release the mouse button, stop the timer and hold current position. else if (~held & change & CONTROL_ML_LBUTTON) { llSetTimerEvent(0); llMoveToTarget(llGetPos(), 0.1); llSetColor(<1,0,0>,ALL_SIDES); } } // Each tick, trigger the Move routine above. timer() { Move(); } }