Jump to content

Jesrad Seraph

Resident
  • Posts

    2
  • Joined

  • Last visited

Reputation

5 Neutral

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Here is the autopilot script adapted to a single linkset, just put the script in any part of it, add the destinations notecard to make it start. This requires no other script. // MonoMove autopilot // // Reads a notecard for destinations list string note = "destinations"; integer running; key req; integer line; string last; vector va; vector vb; vector vta; vector vtb; rotation ra; rotation rb; vector vt; rotation rt; float dist; float angle; vector axis; integer steps; float off; float offa; float offb; float speed; float next_speed; float t; float u; float rate = 0.0625; float rad = 0.425; float corr = 1.9; float banking = -3.14159; float tilting = 3.0; // one fourth the vertical tilt of the trajectory, set to 0.0 for full tilt, -2.0 for reverse list stack; // Notecard code: //v speed set speed //d <dest> <orient> speed go to destination (region) and turn to orientation and accelerate to speed using Hermit curve //D <dest> <orient> speed go to destination (grid) and turn to orientation and accelerate to speed using Hermit curve //r <orient> rspeed turn to orient at speed //w delay wait delay //j line-offset skip line-offset next lines //J line jump to line //c condition [arg1, ...] skip next line if condition true // condition: // 1 range = owner sensed // 2 range = other av sensed // 3 arg = random [0-1] < arg ? // 4 stack == arg ? //s channel text say text on channel //S channel text shout text on channel //l value store value on stack //u remove topmost value from stack //p value increment topmost in stack by value move() { llSetTimerEvent(rate); va = llGetRootPosition();// + llGetRegionCorner(); ra = llGetRootRotation(); vta = llRot2Fwd(ra); vtb = llRot2Fwd(rb); off = llSqrt(speed / next_speed); dist = rad * llVecMag(vb - va); vta = (dist * off * vta); vtb = (dist * vtb / off); dist = corr * (llVecMag(vta) + llVecMag(vta - vtb) + llVecMag(vtb)); vta = va + vta; vtb = vb - vtb; steps = llCeil(dist / (speed + next_speed)); float f = 1.0 / steps; offa = f * off; offb = f / off; t = 0.0; u = 1.0; } flat() { rt = llGetRootRotation(); vt = llRot2Fwd(rt); va = <vt.x, vt.y, .0>; rt = llRotBetween(<1,0,0>, va) * llRotBetween(va, vt); vt = llGetRootPosition(); llSetLinkPrimitiveParamsFast(LINK_ROOT, [PRIM_POSITION, vt, PRIM_ROTATION, rt]); } next_move() { vector v; vector vh; vector vo; t = t + (t * offb + u * offa); u = 1.0 - t; //vector corner = llGetRegionCorner(); v = vt; vo = llRot2Left(rt); //vt = (u*u*u*(va - corner) + 3*t*u*u*(vta - corner) + 3*t*t*u*(vtb - corner) + t*t*t*(vb - corner)); vt = (u*u*u*va + 3*t*u*u*vta + 3*t*t*u*vtb + t*t*t*vb); v = (vt - v); vh = <v.x, v.y, .0>; float f = v * vo; if (llFabs(f) > 0.0078125) rt = llEuler2Rot(<banking * (v * vo), .0, .0>) * llRotBetween(<1,0,0>, vh) * llRotBetween(vh, v + (tilting * vh)); else rt = llRotBetween(<1,0,0>, vh) * llRotBetween(vh, v + (tilting * vh)); } default { on_rez(integer p) { llResetScript(); } state_entry() { llSetText("", ZERO_VECTOR, 0.0); if (llGetInventoryType(note) == INVENTORY_NOTECARD) { state read; } } touch_start(integer p) { if (llDetectedKey(0) != llGetOwner()) return; llOwnerSay("d!" + (string)llGetRootPosition() + "!" + (string)llGetRootRotation()); } changed(integer c) { if (c & CHANGED_INVENTORY) { if (llGetInventoryType(note) == INVENTORY_NOTECARD) llResetScript(); } } } state read { state_entry() { req = llGetNotecardLine(note, line = 0); speed = 0.003125; next_speed = 0.003125; running = TRUE; llSetText("", ZERO_VECTOR, 0.0); } touch_start(integer c) { if (running) { running = FALSE; llSetTimerEvent(0.0); req = NULL_KEY; llSetText("Stopped", <1,0,0>, 1.0); } else { llSetText("", ZERO_VECTOR, 0.0); req = llGetNotecardLine(note, line); } } dataserver(key r, string s) { if (r != req) return; list ins = llParseString2List(s, ["!", "+", ";", "/"], []); string prefix = llList2String(ins, 0); //llSetText("Executing:\n" + s + "\n \n \n ", <1,1,1>, 1.0); if (prefix == "d") { vb = (vector)llList2String(ins, 2); if (vb != ZERO_VECTOR) rb = llEuler2Rot(DEG_TO_RAD * vb); else rb = (rotation)llList2String(ins, 2); vb = (vector)llList2String(ins, 1);// + llGetRegionCorner(); next_speed = llFabs((float)llList2String(ins, 3)); if (next_speed < 0.003125) next_speed = 0.003125; move(); return; } else if (prefix == "D") { vb = (vector)llList2String(ins, 2) - llGetRegionCorner(); if (vb != ZERO_VECTOR) rb = llEuler2Rot(DEG_TO_RAD * vb); else rb = (rotation)llList2String(ins, 2); vb = (vector)llList2String(ins, 1); next_speed = llFabs((float)llList2String(ins, 3)); if (next_speed < 0.003125) next_speed = 0.003125; move(); return; } else if (prefix == "r") { integer i; flat(); ra = llGetRootRotation(); va = llGetRootPosition();// + llGetRegionCorner(); rb = (rotation)llList2String(ins, 1); vta = llRot2Fwd(ra); vtb = llRot2Fwd(rb); vt = vtb; vt.z = 0.0; rt = llRotBetween(vt, vtb) * llRotBetween(vta, vt); offa = llFabs((float)llList2String(ins, 2)); angle = llRot2Angle(rt); axis = llRot2Axis(rt); if ((llFabs(angle) > 0.03125) && (offa > 0.0)) { steps = llCeil(llFabs(angle) / offa); offa = 1.0 / steps; for (t = .0; t < 1.0; t = t + offa) { llSetLinkPrimitiveParamsFast(LINK_ROOT, [PRIM_POSITION, va, PRIM_ROTATION, ra * llAxisAngle2Rot(axis, t * angle)]); llSleep(rate); } llSetLinkPrimitiveParamsFast(LINK_ROOT, [PRIM_POSITION, va, PRIM_ROTATION, (rotation)llList2String(ins, 1)]); } } else if (prefix == "w") { flat(); llSleep((float)llList2String(ins, 1)); } else if (prefix == "v") { speed = (float)llList2String(ins, 1); if (llFabs(speed) < 0.03125) speed = 0.03125; else if (speed < 0.0) speed = -speed; } else if (prefix == "j") { line = line + (integer)llList2String(ins, 1) - 1; } else if (prefix == "J") { line = (integer)llList2String(ins, 1) - 1; } else if (prefix == "s") { llSay((integer)llList2String(ins, 1), llList2String(ins, 2)); } else if (prefix == "S") { llShout((integer)llList2String(ins, 1), llList2String(ins, 2)); } else if (prefix == "l") { integer a = (integer)llList2String(ins, 2); stack = [a] + stack; } else if (prefix == "p") { integer b = (integer)llList2String(ins, 2); if (llGetListLength(stack) > 0) { integer a = llList2Integer(stack, 0); if (llGetListLength(stack) > 1) { stack = [a + b] + llList2List(stack, 1, -1); } else stack = [a + b]; } } else if (prefix == "u") { if (llGetListLength(stack) > 1) stack = llList2List(stack, 1, -1); else stack = []; } else if (prefix == "c") { integer arg = (integer)llList2String(ins, 1); if (arg == 1) { llSensor("", llGetOwner(), AGENT, (float)llList2String(ins, 2), PI); return; } if (arg == 2) { llSensor("", "", AGENT, (float)llList2String(ins, 2), PI); return; } if (arg == 3) { float a = (float)llList2String(ins, 2); if (llFrand(1.0) > a) { line += 2; req = llGetNotecardLine(note, line); return; } } else if (arg == 4) { integer a = (integer)llList2String(ins, 2); if (llList2Integer(stack, 0) == a) { line += 2; req = llGetNotecardLine(note, line); return; } } } req = llGetNotecardLine(note, ++line); } timer() { next_move(); llSetLinkPrimitiveParamsFast(LINK_ROOT, [PRIM_POSITION, vt, PRIM_ROTATION, rt]); if (t > 1.0) { req = llGetNotecardLine(note, ++line); llSetTimerEvent(0.0); speed = next_speed; } } sensor(integer c) { req = llGetNotecardLine(note, ++line); } no_sensor() { line += 2; req = llGetNotecardLine(note, line); } }
  2. Hello everyone, Having just reinstalled an SL viewer for the first time in... counting... 14 years now, because there are still people DMing me about products using my MultiMove and NonPhy series of scripts, I would like to have the whole series of scripts readily available for everyone, under the WTFPL, with basic explanations. MultiMove is a series of 6 scripts meant to create non-physical vehicles out of pretty much anything, up to and including builds composed of multiple separate linksets. I had initially made these scripts to make a sim-sized flying castle driveable. This is version 7, which has a specialized MonoMove script for single linkset vehicles, a Shuttle script for turning a distinct linkset that is part of a MultiMove set into a detachable vehicle independently of the rest of the build (but able to rejoin into the original set once uncontrolled), and an Autopilot script that can drive a MultiMove set by generating positions using Hermite curves (think "Bezier curves" in 3D) from instructions provided by a Notecard (with basic conditional instructions too, so you can have automated tours that trigger or pause based on the presence of a sensor target). It shouldn't be very hard to adapt the Autopilot to MonoMove (just switch from Shouting to updating the position and rotation of the root directly). How it works: The main driving script goes in the pilot seat which should be a child part of the central linkset (the one that will act as the pivoting center for the whole build). The mover script go in the root part of each linkset composing the build you want to turn into a vehicle. When the scripts initialize each linkset takes a measure of its offset from the central linkset, then the driving script simply Shouts the new position they should keep offsetting from (rotation included). It's very simple, though it's easy to get the maths wrong. It uses whole-grid coordinates to make crossing sim border simple. Previous versions used multiple Mover scripts in the root of each linkset, each on a sequential channel, with the driving script switching between those channels in order to update the position faster, but later updates to SL made this unnecessary, you can still see some of the code commented out for this. You will want to customize the value "offchan" for each vehicle you make so they don't risk overlapping or messing with other MultiMove vehicles. Extra: The format for the autopilot notecard is detailed in the script's comments, along with a basic example you can try yourself. This works by supplying waypoints (in sim or grid coordinates) and set speed and rotation to aim for at these specific points, then the script interpolates between the current waypoint's position, rotation and speed with those of the next waypoint, using fancy maths to make the trajectory perfectly smooth. It also has basic "jump to line #" and "wait N seconds" and conditionals (sensing for ower, sensing for any avatar, stack handling, and a random threshold) for more elaborate programming. Main script: // MultiMove Controller Script // // Manages pilot seat, remote control and movement for the whole set integer offchan = -100; // this is the unique identifier for this type of vehicle integer unichan; // the channel used by the controller and objects to // sync and move, will be composed of this and part // of your UUID integer controlstaken; // control keys taken by the script, initialised later //integer listener; //integer maxl = 8; float rate = 0.05; // interval between updates integer my_chan = 129; // channel for remote commands integer handle; vector sitoffset = <0.25,0,-0.25>; // sitting position rotation sitrot = ZERO_ROTATION; // sitting rotation vector camoffset = ZERO_VECTOR; // camera position (static) vector camtarget = ZERO_VECTOR; // camera direction (static) float speed = 2.0; // distance to move within rate float vspeed = 1.0; // vertical distance to move within rate float lspeed = 1.0; // lateral distance to move within rate float rspeed = 0.062831853; // angle in radians to rotate left or right within rate float inertia = 0.8; float moment = 0.5; vector accel = <0.0625, 0.0625, 0.03125>; // acceleration rates fwd, strafe and vert float raccel = 0.03125; // turning acceleration rate float banking = -0.5; // how much the vehicle banks in turns with forward speed float tilting = 0.125; // how much the vehicle tilts fore and aft with forward accel vector velocity; float rotacity; float azimut; integer pressed; rotation rtarget; list cam = [CAMERA_ACTIVE, TRUE, CAMERA_BEHINDNESS_ANGLE, 180.0, CAMERA_BEHINDNESS_LAG, 0.5, CAMERA_POSITION_LAG, 1.0, CAMERA_FOCUS_LAG, 0.5, CAMERA_POSITION_LOCKED, TRUE]; // camera positions vector neutral = <-32, 0, 8>; vector back = <27, -5, 5>; vector down = <-16, 0, 48>; vector up = <-32, 0, -12>; vector out = <0, 48, 8>; float cam_vel = 0.5; // velocity at which camera will switch, so that you can maneuver at slow speed from angles default { on_rez(integer c) { llSleep(1.6); llResetScript(); } state_entry() { unichan = offchan - (integer)("0x" + llGetSubString((string)llGetOwner(), 0, 6)); llSetTimerEvent(0.0); velocity = ZERO_VECTOR; rotacity = 0.0; vector temp = llRot2Fwd(llGetRootRotation()); temp.z = 0.0; llVecNorm(temp); azimut = llAcos(temp.x); if (llAsin(temp.y) < 0.0) azimut = -azimut; llMinEventDelay(0.05); llSitTarget(sitoffset, sitrot); llSetCameraAtOffset(camtarget); llSetCameraEyeOffset(camoffset); // for (listener = 0; listener < maxl; listener = listener + 1) llShout(unichan, (string)(llGetRootPosition() + llGetRegionCorner()) + "*" + (string)rtarget); handle = llListen(my_chan, "", "", ""); controlstaken = CONTROL_FWD|CONTROL_BACK|CONTROL_ROT_LEFT|CONTROL_ROT_RIGHT|CONTROL_LEFT|CONTROL_RIGHT|CONTROL_UP|CONTROL_DOWN; } changed(integer c) { if (c & CHANGED_LINK) { key id = llAvatarOnSitTarget(); if (id != NULL_KEY) { if (id == llGetOwner()) { llRequestPermissions(id, PERMISSION_TAKE_CONTROLS|PERMISSION_CONTROL_CAMERA); } else llUnSit(id); } else { llReleaseControls(); llSetTimerEvent(0.0); } } } run_time_permissions(integer p) { if (p & PERMISSION_TAKE_CONTROLS) { //integer n; rtarget = llGetRootRotation(); velocity = ZERO_VECTOR; rotacity = 0.0; vector temp = llRot2Fwd(llGetRootRotation()); temp.z = 0.0; llVecNorm(temp); azimut = llAtan2(temp.y, temp.x); // for (n=0; n<maxl; ++n) llShout(unichan, (string)(llGetRootPosition() + llGetRegionCorner()) + "*" + (string)rtarget); llSleep(1.0); llTakeControls(controlstaken, TRUE, FALSE); llSetTimerEvent(rate); llSetCameraParams(cam + [CAMERA_POSITION, neutral * rtarget + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); } else { llReleaseControls(); } } listen(integer chan, string name, key id, string msg) { if ((llGetOwner() != id) && (llGetOwnerKey(id) != llGetOwner())) return; string t = llGetSubString(msg, 0, 0); if (t == "k") { llSetTimerEvent(0.0); llShout(unichan, "k"); } else if (t == "s") { // integer i; // for (i=0; i<maxl ; ++i) llShout(unichan, "s"); llSetTimerEvent(0.0); return; } integer val = (integer)llDeleteSubString(msg, 0, 0); llSetTimerEvent(rate); if (t == "m") { if (val > 0) pressed = pressed | CONTROL_FWD; else if (val < 0) pressed = pressed | CONTROL_BACK; else pressed = pressed & ~(CONTROL_FWD | CONTROL_BACK); } else if (t == "v") { if (val > 0) pressed = pressed | CONTROL_UP; else if (val < 0) pressed = pressed | CONTROL_DOWN; else pressed = pressed & ~(CONTROL_UP | CONTROL_DOWN); } else if (t == "l") { if (val > 0) pressed = pressed | CONTROL_LEFT; else if (val < 0) pressed = pressed | CONTROL_RIGHT; else pressed = pressed & ~(CONTROL_LEFT | CONTROL_RIGHT); } else if (t == "r") { if (val > 0) pressed = pressed | CONTROL_ROT_LEFT; else if (val < 0) pressed = pressed | CONTROL_ROT_RIGHT; else pressed = pressed & ~(CONTROL_ROT_LEFT | CONTROL_ROT_RIGHT); } } control(key id, integer level, integer edge) { pressed = level; } timer() { vector pos = llGetRootPosition() + llGetRegionCorner(); rotation orig = llGetRootRotation(); // listener = (listener + 1) % maxl; integer cam_set = FALSE; float oldvel = velocity.x; float bank = 0.0; float tilt = 0.0; if (pressed & CONTROL_FWD) { velocity.x += accel.x; if (velocity.x > speed) velocity.x = speed; if (velocity.x > cam_vel) { llSetCameraParams([CAMERA_POSITION, neutral * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); cam_set = TRUE; } } else if (pressed & CONTROL_BACK) { velocity.x -= accel.x; if (velocity.x < -speed) velocity.x = -speed; if (velocity.x < -cam_vel) { llSetCameraParams([CAMERA_POSITION, back * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); cam_set = TRUE; } } else velocity.x *= inertia; if (pressed & CONTROL_UP) { velocity.z += accel.z; if (velocity.z > vspeed) velocity.z = vspeed; if ((cam_set == FALSE) && (velocity.z > cam_vel)) { llSetCameraParams([CAMERA_POSITION, out * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); cam_set = TRUE; } } else if (pressed & CONTROL_DOWN) { velocity.z -= accel.z; if (velocity.z < -vspeed) velocity.z = -vspeed; if ((cam_set == FALSE) && (velocity.z < -cam_vel)) { llSetCameraParams([CAMERA_POSITION, up * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); cam_set = TRUE; } } else velocity.z *= inertia; if (pressed & CONTROL_LEFT) { velocity.y += accel.y; if (velocity.y > lspeed) velocity.y = lspeed; if ((cam_set == FALSE) && (velocity.y > cam_vel)) llSetCameraParams([CAMERA_POSITION, down * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); } else if (pressed & CONTROL_RIGHT) { velocity.y -= accel.y; if (velocity.y < -lspeed) velocity.y = -lspeed; if ((cam_set == FALSE) && (velocity.y < -cam_vel)) llSetCameraParams([CAMERA_POSITION, down * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); } else velocity.y *= inertia; if (pressed & CONTROL_ROT_LEFT) { rotacity += raccel; if (rotacity > rspeed) rotacity = rspeed; } else if (pressed & CONTROL_ROT_RIGHT) { rotacity -= raccel; if (rotacity < -rspeed) rotacity = -rspeed; } else rotacity *= moment; if (llFabs(rotacity) > 0.005) { azimut += rotacity; bank = rotacity * banking * velocity.x; tilt = tilting * (velocity.x - oldvel); orig = llEuler2Rot(<bank, tilt, 0.0>) * llEuler2Rot(<0,0,azimut>); llShout(unichan, (string)(pos + velocity * orig) + "*" + (string)orig); } else if (llVecMag(velocity) > 0.01) { tilt = tilting * (velocity.x - oldvel); orig = llEuler2Rot(<0.0, tilt, 0.0>) * llEuler2Rot(<0,0,azimut>); llShout(unichan, (string)(pos + velocity * orig) + "*" + (string)orig); } } } Mover script (goes in the root of each linkset): // Move // // Multimove follower integer offchan = -100; // this is the unique identifier for this type of vehicle integer unichan; // the channel used by the controller and objects to // sync and move, will be composed of this and part // of your UUID integer handle; // handle for the listen function vector my_offset; // original offset, set at first activation rotation my_orientation; // original rotation, set at first activation //integer my_num; // position in the chain of redundancy float azimut; vector old_offset; rotation old_orientation; default { on_rez(integer p) { unichan = offchan - (integer)("0x" + llGetSubString((string)llGetOwner(), 0, 6)); llListenRemove(handle); handle = llListen(unichan, "", "", ""); } state_entry() { unichan = offchan - (integer)("0x" + llGetSubString((string)llGetOwner(), 0, 6)); //my_num = (integer)llGetSubString(llGetScriptName(), -1, -1); handle = llListen(unichan, "", "", ""); } listen(integer chan, string name, key id, string mesg) { if (mesg == "k") llDie(); else if (mesg == "s") return; integer index = llSubStringIndex(mesg, "*"); my_offset = llGetPos() + llGetRegionCorner() - (vector)llGetSubString(mesg, 0, index - 1); my_orientation = llGetRot() / (rotation)(llDeleteSubString(mesg, 0, index)); my_offset = my_offset / llGetRot(); state running; } state_exit() { llListenRemove(handle); } } state running { on_rez(integer p) { unichan = offchan - (integer)("0x" + llGetSubString((string)llGetOwner(), 0, 6)); llListenRemove(handle); handle = llListen(unichan, "", "", ""); } state_entry() { handle = llListen(unichan, "", "", ""); } listen(integer chan, string name, key id, string mesg) { if (mesg == "k") { llDie(); } else if (mesg == "s") { state default; } else { integer index = llSubStringIndex(mesg, "*"); rotation rtarget = my_orientation * (rotation)llDeleteSubString(mesg, 0, index); vector target = my_offset * rtarget + (vector)llGetSubString(mesg, 0, index - 1) - llGetRegionCorner(); llSetLinkPrimitiveParamsFast(LINK_ROOT, [PRIM_POSITION, target, PRIM_ROTATION, rtarget]); } } link_message(integer source, integer code, string s, key id) { if (s == "detach") { if (my_offset == ZERO_VECTOR) return; llListenRemove(handle); old_orientation = my_orientation; my_orientation = ZERO_ROTATION; old_offset = my_offset; my_offset = ZERO_VECTOR; handle = llListen(code, "", "", ""); } else if (s == "attach") { if (old_offset == ZERO_VECTOR) return; llListenRemove(handle); my_orientation = old_orientation; my_offset = old_offset; handle = llListen(unichan, "", "", ""); } } state_exit() { llListenRemove(handle); } } Shuttle single-linkset detachable control script (goes in the pilot seat of the detachable shuttle object): // MultiMove Shuttle Controller Script // // Manages pilot seat, remote control and movement for a specific detachable object of a multimove set integer offchan = -100; // this is the unique identifier for this type of vehicle integer unichan; // the channel used by the controller and objects to // sync and move, will be composed of this and part // of your UUID integer shuttlechan; // set randomly integer controlstaken; // control keys taken by the script, initialised later //integer listener; //integer maxl = 8; float rate = 0.05; // interval between updates vector sitoffset = <0.25,0,0.35>; // sitting position rotation sitrot = ZERO_ROTATION; // sitting rotation vector camoffset = ZERO_VECTOR; // camera position (static) vector camtarget = ZERO_VECTOR; // camera direction (static) float speed = 2.0; // distance to move within rate float vspeed = 1.0; // vertical distance to move within rate float lspeed = 1.0; // lateral distance to move within rate float rspeed = 0.062831853; // angle in radians to rotate left or right within rate float inertia = 0.8; float moment = 0.5; vector accel = <0.0625, 0.0625, 0.03125>; // acceleration rates fwd, strafe and vert float raccel = 0.03125; // turning acceleration rate float banking = -0.5; // how much the vehicle banks in turns with forward speed float tilting = 0.125; // how much the vehicle tilts fore and aft with forward accel vector velocity; float rotacity; float azimut; integer pressed; rotation rtarget; list cam = [CAMERA_ACTIVE, TRUE, CAMERA_BEHINDNESS_ANGLE, 180.0, CAMERA_BEHINDNESS_LAG, 0.5, CAMERA_POSITION_LAG, 1.0, CAMERA_FOCUS_LAG, 0.5, CAMERA_POSITION_LOCKED, TRUE]; // camera positions vector neutral = <-9, 0, 2>; vector back = <6, -3, 1>; vector down = <-7, 0, 8>; vector up = <-9, 0, -2>; vector out = <0, 9, 3>; float cam_vel = 0.25; // velocity at which camera will switch, so that you can maneuver at slow speed from angles default { on_rez(integer c) { llSleep(1.6); llResetScript(); } state_entry() { unichan = offchan - (integer)("0x" + llGetSubString((string)llGetOwner(), 0, 6)); llSetTimerEvent(0.0); velocity = ZERO_VECTOR; rotacity = 0.0; vector temp = llRot2Fwd(llGetRootRotation()); temp.z = 0.0; llVecNorm(temp); azimut = llAcos(temp.x); if (llAsin(temp.y) < 0.0) azimut = -azimut; llMinEventDelay(0.05); llSitTarget(sitoffset, sitrot); llSetCameraAtOffset(camtarget); llSetCameraEyeOffset(camoffset); controlstaken = CONTROL_FWD|CONTROL_BACK|CONTROL_ROT_LEFT|CONTROL_ROT_RIGHT|CONTROL_LEFT|CONTROL_RIGHT|CONTROL_UP|CONTROL_DOWN; do { shuttlechan = (integer)llFrand(500000000) + 11; } while (llAbs(shuttlechan - unichan) < 10); } changed(integer c) { if (c & CHANGED_LINK) { key id = llAvatarOnSitTarget(); if (id != NULL_KEY) { if (id == llGetOwner()) { llRequestPermissions(id, PERMISSION_TAKE_CONTROLS|PERMISSION_CONTROL_CAMERA); } else llUnSit(id); } else { llReleaseControls(); llSetTimerEvent(0.0); llMessageLinked(LINK_ROOT, 0, "attach", ""); } } } run_time_permissions(integer p) { if (p & PERMISSION_TAKE_CONTROLS) { integer n; llMessageLinked(LINK_ROOT, shuttlechan, "detach", ""); rtarget = llGetRootRotation(); velocity = ZERO_VECTOR; rotacity = 0.0; vector temp = llRot2Fwd(llGetRootRotation()); temp.z = 0.0; llVecNorm(temp); azimut = llAcos(temp.x); if (llAsin(temp.y) < 0.0) azimut = -azimut; llSleep(1.0); llTakeControls(controlstaken, TRUE, FALSE); llSetTimerEvent(rate); llSetCameraParams(cam + [CAMERA_POSITION, neutral * rtarget + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); // for (n=0; n<maxl; ++n) llShout(shuttlechan, (string)(llGetRootPosition() + llGetRegionCorner()) + "*" + (string)rtarget); } else { llReleaseControls(); } } control(key id, integer level, integer edge) { pressed = level; } timer() { vector pos = llGetRootPosition() + llGetRegionCorner(); rotation orig = llGetRootRotation(); // listener = (listener + 1) % maxl; integer cam_set = FALSE; float oldvel = velocity.x; float bank = 0.0; float tilt = 0.0; if (pressed & CONTROL_FWD) { velocity.x += accel.x; if (velocity.x > speed) velocity.x = speed; if (velocity.x > cam_vel) { llSetCameraParams([CAMERA_POSITION, neutral * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); cam_set = TRUE; } } else if (pressed & CONTROL_BACK) { velocity.x -= accel.x; if (velocity.x < -speed) velocity.x = -speed; if (velocity.x < -cam_vel) { llSetCameraParams([CAMERA_POSITION, back * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); cam_set = TRUE; } } else velocity.x *= inertia; if (pressed & CONTROL_UP) { velocity.z += accel.z; if (velocity.z > vspeed) velocity.z = vspeed; if ((cam_set == FALSE) && (velocity.z > cam_vel)) { llSetCameraParams([CAMERA_POSITION, out * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); cam_set = TRUE; } } else if (pressed & CONTROL_DOWN) { velocity.z -= accel.z; if (velocity.z < -vspeed) velocity.z = -vspeed; if ((cam_set == FALSE) && (velocity.z < -cam_vel)) { llSetCameraParams([CAMERA_POSITION, up * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); cam_set = TRUE; } } else velocity.z *= inertia; if (pressed & CONTROL_LEFT) { velocity.y += accel.y; if (velocity.y > lspeed) velocity.y = lspeed; if ((cam_set == FALSE) && (velocity.y > cam_vel)) llSetCameraParams([CAMERA_POSITION, down * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); } else if (pressed & CONTROL_RIGHT) { velocity.y -= accel.y; if (velocity.y < -lspeed) velocity.y = -lspeed; if ((cam_set == FALSE) && (velocity.y < -cam_vel)) llSetCameraParams([CAMERA_POSITION, down * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); } else velocity.y *= inertia; if (pressed & CONTROL_ROT_LEFT) { rotacity += raccel; if (rotacity > rspeed) rotacity = rspeed; } else if (pressed & CONTROL_ROT_RIGHT) { rotacity -= raccel; if (rotacity < -rspeed) rotacity = -rspeed; } else rotacity *= moment; if (llFabs(rotacity) > 0.005) { azimut += rotacity; bank = rotacity * banking * velocity.x; tilt = tilting * (velocity.x - oldvel); orig = llEuler2Rot(<bank, tilt, 0.0>) * llEuler2Rot(<0,0,azimut>); llShout(shuttlechan, (string)(pos + velocity * orig) + "*" + (string)orig); } else if (llVecMag(velocity) > 0.01) { tilt = tilting * (velocity.x - oldvel); orig = llEuler2Rot(<0.0, tilt, 0.0>) * llEuler2Rot(<0,0,azimut>); llShout(shuttlechan, (string)(pos + velocity * orig) + "*" + (string)orig); } } } Autopilot script (still a bit experimental): // MultiMove autopilot // // Reads a notecard for destinations list string note = "destinations"; integer offchan = -100; // direct drive channel integer chan; integer running; key req; integer line; string last; vector va; vector vb; vector vta; vector vtb; rotation ra; rotation rb; vector vt; rotation rt; float dist; float angle; vector axis; integer steps; //integer mul = 0; //integer max = 8; float off; float offa; float offb; float speed; float next_speed; float t; float u; float rate = 0.05; float rad = 0.425; float corr = 1.9; float banking = -3.14159; float tilting = 3.0; // one fourth the vertical tilt of the trajectory, set to 0.0 for full tilt, -2.0 for reverse list stack; // Notecard code: //v speed set speed //d <dest> <orient> speed go to destination (region) and turn to orientation and accelerate to speed using Hermit curve //D <dest> <orient> speed go to destination (grid) and turn to orientation and accelerate to speed using Hermit curve //r <orient> rspeed turn to orient at speed //w delay wait delay //g line goto line //j line-offset skip line-offset next lines //J line jump to line //c condition [arg1, ...] skip next line if condition true // condition: // 1 range = owner sensed // 2 range = other av sensed // 3 arg = random [0-1] < arg ? // 4 stack == arg ? //s channel text say text on channel //S channel text shout text on channel //o channel set offchan to channel //l value store value on stack //u remove topmost value from stack //p value increment topmost in stack by value // Example notecard: //o!-1100 //v!0.2 //d!<120,128,32>!<0,0,0>!0.4 //c!1!4.0 //j!4 //s!0!Owner not found, waiting 5 seconds //w!5 //J!-3 //s!0!Owner found, starting //d!<128,128,32>!<0,0,0>!0.4 //d!<180,128,40>!<0,0,0>!0.666 //d!<180,180,48>!<0,0,90>!0.7 //d!<128,180,56>!<0,0,180>!0.75 //d!<128,128,60>!<0,0,270>!0.75 //d!<180,128,64>!<0,0,0>!0.75 //d!<180,180,64>!<0,0,90>!0.75 //d!<128,180,64>!<0,0,180>!0.75 //d!<128,128,64>!<0,0,270>!0.75 //c!1!16.0 //j!-5 //d!<128,128,32>!<0,0,0>!0.4 //J!3 move() { llSetTimerEvent(rate); va = llGetRootPosition() + llGetRegionCorner(); ra = llGetRootRotation(); vta = llRot2Fwd(ra); vtb = llRot2Fwd(rb); off = llSqrt(speed / next_speed); dist = rad * llVecMag(vb - va); vta = (dist * off * vta); vtb = (dist * vtb / off); dist = corr * (llVecMag(vta) + llVecMag(vta - vtb) + llVecMag(vtb)); vta = va + vta; vtb = vb - vtb; steps = llCeil(dist / (speed + next_speed)); float f = 1.0 / steps; offa = f * off; offb = f / off; t = 0.0; u = 1.0; } flat() { rt = llGetRootRotation(); vt = llRot2Fwd(rt); va = <vt.x, vt.y, .0>; rt = llRotBetween(<1,0,0>, va) * llRotBetween(va, vt); // mul = (mul + 1) % max; vt = llGetRootPosition(); llShout(chan, (string)(vt + llGetRegionCorner()) + "*" + (string)rt); } next_move() { vector v; vector vh; vector vo; t = t + (t * offb + u * offa); u = 1.0 - t; // mul = (mul + 1) % max; vector corner = llGetRegionCorner(); v = vt; vo = llRot2Left(rt); vt = (u*u*u*(va - corner) + 3*t*u*u*(vta - corner) + 3*t*t*u*(vtb - corner) + t*t*t*(vb - corner)); v = (vt - v); vh = <v.x, v.y, .0>; float f = v * vo; if (llFabs(f) > 0.0078125) rt = llEuler2Rot(<banking * (v * vo), .0, .0>) * llRotBetween(<1,0,0>, vh) * llRotBetween(vh, v + (tilting * vh)); else rt = llRotBetween(<1,0,0>, vh) * llRotBetween(vh, v + (tilting * vh)); } default { on_rez(integer p) { llResetScript(); } state_entry() { llSetText("", ZERO_VECTOR, 0.0); if (llGetInventoryType(note) == INVENTORY_NOTECARD) { state read; } } touch_start(integer p) { if (llDetectedKey(0) != llGetOwner()) return; llOwnerSay("d!" + (string)llGetRootPosition() + "!" + (string)llGetRootRotation()); } changed(integer c) { if (c & CHANGED_INVENTORY) { if (llGetInventoryType(note) == INVENTORY_NOTECARD) llResetScript(); } } } state read { on_rez(integer p) { chan = offchan - (integer)("0x" + llGetSubString((string)llGetOwner(), 0, 6)); } state_entry() { chan = offchan - (integer)("0x" + llGetSubString((string)llGetOwner(), 0, 6)); req = llGetNotecardLine(note, line = 0); speed = 0.003125; next_speed = 0.003125; running = TRUE; } touch_start(integer c) { if (running) { running = FALSE; llSetTimerEvent(0.0); req = NULL_KEY; llSetText("Stopped", <1,0,0>, 1.0); } else { llSetText("", ZERO_VECTOR, 0.0); req = llGetNotecardLine(note, line); } } dataserver(key r, string s) { if (r != req) return; list ins = llParseString2List(s, ["+", "!", ";", "/"], []); string prefix = llList2String(ins, 0); //llSetText("Executing:\n" + s + "\n \n \n ", <1,1,1>, 1.0); if (prefix == "d") { vb = (vector)llList2String(ins, 2); if (vb != ZERO_VECTOR) rb = llEuler2Rot(DEG_TO_RAD * vb); else rb = (rotation)llList2String(ins, 2); vb = (vector)llList2String(ins, 1) + llGetRegionCorner(); next_speed = llFabs((float)llList2String(ins, 3)); if (next_speed < 0.003125) next_speed = 0.003125; move(); return; } else if (prefix == "D") { vb = (vector)llList2String(ins, 2); if (vb != ZERO_VECTOR) rb = llEuler2Rot(DEG_TO_RAD * vb); else rb = (rotation)llList2String(ins, 2); vb = (vector)llList2String(ins, 1); next_speed = llFabs((float)llList2String(ins, 3)); if (next_speed < 0.003125) next_speed = 0.003125; move(); return; } else if (prefix == "r") { integer i; flat(); ra = llGetRootRotation(); va = llGetRootPosition() + llGetRegionCorner(); string tpos = (string)va + "*"; rb = (rotation)llList2String(ins, 1); vta = llRot2Fwd(ra); vtb = llRot2Fwd(rb); vt = vtb; vt.z = 0.0; rt = llRotBetween(vt, vtb) * llRotBetween(vta, vt); offa = llFabs((float)llList2String(ins, 2)); angle = llRot2Angle(rt); axis = llRot2Axis(rt); if ((llFabs(angle) > 0.03125) && (offa > 0.0)) { steps = llCeil(llFabs(angle) / offa); offa = 1.0 / steps; // mul = (mul + 1) % max; for (t = .0; t < 1.0; t = t + offa) { llShout(chan, tpos + (string)(ra * llAxisAngle2Rot(axis, t * angle)) ); // mul = (mul + 1) % max; llSleep(rate); } llShout(chan, tpos + llList2String(ins, 1)); } } else if (prefix == "w") { flat(); llSleep((float)llList2String(ins, 1)); } else if (prefix == "o") { offchan = (integer)llList2String(ins, 1); chan = offchan - (integer)("0x" + llGetSubString((string)llGetOwner(), 0, 6)); } else if (prefix == "v") { speed = (float)llList2String(ins, 1); if (llFabs(speed) < 0.03125) speed = 0.03125; else if (speed < 0.0) speed = -speed; } else if (prefix == "g") { line = (integer)llList2String(ins, 1) - 1; } else if (prefix == "j") { line = line + (integer)llList2String(ins, 1) - 1; } else if (prefix == "J") { line = (integer)llList2String(ins, 1) - 1; } else if (prefix == "s") { llSay((integer)llList2String(ins, 1), llList2String(ins, 2)); } else if (prefix == "S") { llShout((integer)llList2String(ins, 1), llList2String(ins, 2)); } else if (prefix == "l") { integer a = (integer)llList2String(ins, 2); stack = [a] + stack; } else if (prefix == "p") { integer b = (integer)llList2String(ins, 2); if (llGetListLength(stack) > 0) { integer a = llList2Integer(stack, 0); if (llGetListLength(stack) > 1) { stack = [a + b] + llList2List(stack, 1, -1); } else stack = [a + b]; } } else if (prefix == "u") { if (llGetListLength(stack) > 1) stack = llList2List(stack, 1, -1); else stack = []; } else if (prefix == "c") { integer arg = (integer)llList2String(ins, 1); if (arg == 1) { llSensor("", llGetOwner(), AGENT, (float)llList2String(ins, 2), PI); return; } if (arg == 2) { llSensor("", "", AGENT, (float)llList2String(ins, 2), PI); return; } if (arg == 3) { float a = (float)llList2String(ins, 2); if (llFrand(1.0) > a) { line += 2; req = llGetNotecardLine(note, line); return; } } else if (arg == 4) { integer a = (integer)llList2String(ins, 2); if (llList2Integer(stack, 0) == a) { line += 2; req = llGetNotecardLine(note, line); return; } } } req = llGetNotecardLine(note, ++line); } timer() { next_move(); llShout(chan, (string)(vt + llGetRegionCorner()) + "*" + (string)rt); if (t > 1.0) { req = llGetNotecardLine(note, ++line); llSetTimerEvent(0.0); speed = next_speed; } } sensor(integer c) { req = llGetNotecardLine(note, ++line); } no_sensor() { line += 2; req = llGetNotecardLine(note, line); } } Example "destinations" notecard implementing a simple course triggered by presence of the owner for the autopilot: o!-1100 v!0.2 d!<120,128,32>!<0,0,0>!0.4 c!1!4.0 j!4 s!0!Owner not found, waiting 5 seconds w!5 J!-3 s!0!Owner found, starting d!<128,128,32>!<0,0,0>!0.4 d!<180,128,40>!<0,0,0>!0.666 d!<180,180,48>!<0,0,90>!0.7 d!<128,180,56>!<0,0,180>!0.75 d!<128,128,60>!<0,0,270>!0.75 d!<180,128,64>!<0,0,0>!0.75 d!<180,180,64>!<0,0,90>!0.75 d!<128,180,64>!<0,0,180>!0.75 d!<128,128,64>!<0,0,270>!0.75 c!1!16.0 j!-5 d!<128,128,32>!<0,0,0>!0.4 J!3 MonoMove script (no Mover script required for this one, it is meant for the piloting seat in a single linkset, it will rotate the vehicle after your mouselook): // MonoMove Controller Script // v7 // Manages pilot seat, remote control and movement for the whole set //integer offchan = -100; // this is the unique identifier for this type of vehicle //integer unichan; // the channel used by the controller and objects to // sync and move, will be composed of this and part // of your UUID integer controlstaken; // control keys taken by the script, initialised later //integer listener; //integer maxl = 8; float rate = 0.05; // interval between updates integer my_chan = 129; // channel for remote commands integer handle; vector sitoffset = <0.25,0,-0.25>; // sitting position rotation sitrot = ZERO_ROTATION; // sitting rotation vector camoffset = ZERO_VECTOR; // camera position (static) vector camtarget = ZERO_VECTOR; // camera direction (static) float speed = 2.0; // distance to move within rate float vspeed = 1.0; // vertical distance to move within rate float lspeed = 1.0; // lateral distance to move within rate float rspeed = 0.062831853; // angle in radians to rotate left or right within rate float inertia = 0.8; float moment = 0.5; vector accel = <0.0625, 0.0625, 0.03125>; // acceleration rates fwd, strafe and vert float raccel = 0.03125; // turning acceleration rate float banking = -0.5; // how much the vehicle banks in turns with forward speed float tilting = 0.125; // how much the vehicle tilts fore and aft with forward accel vector velocity; float rotacity; float azimut; integer pressed; rotation rtarget; list cam = [CAMERA_ACTIVE, TRUE, CAMERA_BEHINDNESS_ANGLE, 180.0, CAMERA_BEHINDNESS_LAG, 0.5, CAMERA_POSITION_LAG, 1.0, CAMERA_FOCUS_LAG, 0.5, CAMERA_POSITION_LOCKED, TRUE]; // camera positions vector neutral = <-32, 0, 8>; vector back = <27, -5, 5>; vector down = <-16, 0, 48>; vector up = <-32, 0, -12>; vector out = <0, 48, 8>; float cam_vel = 0.5; // velocity at which camera will switch, so that you can maneuver at slow speed from angles default { on_rez(integer c) { llSleep(1.6); llResetScript(); } state_entry() { //unichan = offchan - (integer)("0x" + llGetSubString((string)llGetOwner(), 0, 6)); llSetTimerEvent(0.0); velocity = ZERO_VECTOR; rotacity = 0.0; vector temp = llRot2Fwd(llGetRootRotation()); temp.z = 0.0; llVecNorm(temp); azimut = llAcos(temp.x); if (llAsin(temp.y) < 0.0) azimut = -azimut; llMinEventDelay(0.05); llSitTarget(sitoffset, sitrot); llSetCameraAtOffset(camtarget); llSetCameraEyeOffset(camoffset); //for (listener = 0; listener < maxl; listener = listener + 1) // llShout(unichan + listener, (string)(llGetRootPosition() + llGetRegionCorner()) + "*" + (string)rtarget); llSetLinkPrimitiveParamsFast(LINK_ROOT, [PRIM_ROTATION, rtarget]); handle = llListen(my_chan, "", "", ""); controlstaken = CONTROL_FWD|CONTROL_BACK|CONTROL_ROT_LEFT|CONTROL_ROT_RIGHT|CONTROL_LEFT|CONTROL_RIGHT|CONTROL_UP|CONTROL_DOWN; } changed(integer c) { if (c & CHANGED_LINK) { key id = llAvatarOnSitTarget(); if (id != NULL_KEY) { if (id == llGetOwner()) { llRequestPermissions(id, PERMISSION_TAKE_CONTROLS|PERMISSION_CONTROL_CAMERA); } else llUnSit(id); } else { llReleaseControls(); llSetTimerEvent(0.0); } } } run_time_permissions(integer p) { if (p & PERMISSION_TAKE_CONTROLS) { integer n; rtarget = llGetRootRotation(); velocity = ZERO_VECTOR; rotacity = 0.0; vector temp = llRot2Fwd(llGetRootRotation()); temp.z = 0.0; llVecNorm(temp); azimut = llAtan2(temp.y, temp.x); //for (n=0; n<maxl; ++n) // llShout(unichan + n, (string)(llGetRootPosition() + llGetRegionCorner()) + "*" + (string)rtarget); llSetLinkPrimitiveParamsFast(LINK_ROOT, [PRIM_ROTATION, rtarget]); llSleep(1.0); llTakeControls(controlstaken, TRUE, FALSE); llSetTimerEvent(rate); llSetCameraParams(cam + [CAMERA_POSITION, neutral * rtarget + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); } else { llReleaseControls(); } } listen(integer chan, string name, key id, string msg) { if ((llGetOwner() != id) && (llGetOwnerKey(id) != llGetOwner())) return; string t = llGetSubString(msg, 0, 0); if (t == "k") { llSetTimerEvent(0.0); llDie(); } else if (t == "s") { integer i; //for (i=0; i<maxl ; ++i) // llShout(unichan + i, "s"); llSetTimerEvent(0.0); return; } integer val = (integer)llDeleteSubString(msg, 0, 0); llSetTimerEvent(rate); if (t == "m") { if (val > 0) pressed = pressed | CONTROL_FWD; else if (val < 0) pressed = pressed | CONTROL_BACK; else pressed = pressed & ~(CONTROL_FWD | CONTROL_BACK); } else if (t == "v") { if (val > 0) pressed = pressed | CONTROL_UP; else if (val < 0) pressed = pressed | CONTROL_DOWN; else pressed = pressed & ~(CONTROL_UP | CONTROL_DOWN); } else if (t == "l") { if (val > 0) pressed = pressed | CONTROL_LEFT; else if (val < 0) pressed = pressed | CONTROL_RIGHT; else pressed = pressed & ~(CONTROL_LEFT | CONTROL_RIGHT); } else if (t == "r") { if (val > 0) pressed = pressed | CONTROL_ROT_LEFT; else if (val < 0) pressed = pressed | CONTROL_ROT_RIGHT; else pressed = pressed & ~(CONTROL_ROT_LEFT | CONTROL_ROT_RIGHT); } } control(key id, integer level, integer edge) { pressed = level; } timer() { vector pos = llGetRootPosition();// + llGetRegionCorner(); rotation orig = llGetRootRotation(); //listener = (listener + 1) % maxl; integer cam_set = FALSE; float oldvel = velocity.x; float bank = 0.0; float tilt = 0.0; if (pressed & CONTROL_FWD) { velocity.x += accel.x; if (velocity.x > speed) velocity.x = speed; if (velocity.x > cam_vel) { llSetCameraParams([CAMERA_POSITION, neutral * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); cam_set = TRUE; } } else if (pressed & CONTROL_BACK) { velocity.x -= accel.x; if (velocity.x < -speed) velocity.x = -speed; if (velocity.x < -cam_vel) { llSetCameraParams([CAMERA_POSITION, back * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); cam_set = TRUE; } } else velocity.x *= inertia; if (pressed & CONTROL_UP) { velocity.z += accel.z; if (velocity.z > vspeed) velocity.z = vspeed; if ((cam_set == FALSE) && (velocity.z > cam_vel)) { llSetCameraParams([CAMERA_POSITION, out * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); cam_set = TRUE; } } else if (pressed & CONTROL_DOWN) { velocity.z -= accel.z; if (velocity.z < -vspeed) velocity.z = -vspeed; if ((cam_set == FALSE) && (velocity.z < -cam_vel)) { llSetCameraParams([CAMERA_POSITION, up * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); cam_set = TRUE; } } else velocity.z *= inertia; if (pressed & CONTROL_LEFT) { velocity.y += accel.y; if (velocity.y > lspeed) velocity.y = lspeed; if ((cam_set == FALSE) && (velocity.y > cam_vel)) llSetCameraParams([CAMERA_POSITION, down * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); } else if (pressed & CONTROL_RIGHT) { velocity.y -= accel.y; if (velocity.y < -lspeed) velocity.y = -lspeed; if ((cam_set == FALSE) && (velocity.y < -cam_vel)) llSetCameraParams([CAMERA_POSITION, down * orig + llGetRootPosition(), CAMERA_FOCUS, llGetRootPosition()]); } else velocity.y *= inertia; if (pressed & CONTROL_ROT_LEFT) { rotacity += raccel; if (rotacity > rspeed) rotacity = rspeed; } else if (pressed & CONTROL_ROT_RIGHT) { rotacity -= raccel; if (rotacity < -rspeed) rotacity = -rspeed; } else rotacity *= moment; if (llFabs(rotacity) > 0.005) { azimut += rotacity; bank = rotacity * banking * velocity.x; tilt = tilting * (velocity.x - oldvel); orig = llEuler2Rot(<bank, tilt, 0.0>) * llEuler2Rot(<0,0,azimut>); //llShout(unichan + listener, (string)(pos + velocity * orig) + "*" + (string)orig); llSetLinkPrimitiveParamsFast(LINK_ROOT, [PRIM_POSITION, (pos + velocity * orig), PRIM_ROTATION, orig]); } else if (llVecMag(velocity) > 0.01) { tilt = tilting * (velocity.x - oldvel); orig = llEuler2Rot(<0.0, tilt, 0.0>) * llEuler2Rot(<0,0,azimut>); //llShout(unichan + listener, (string)(pos + velocity * orig) + "*" + (string)orig); llSetLinkPrimitiveParamsFast(LINK_ROOT, [PRIM_POSITION, (pos + velocity * orig), PRIM_ROTATION, orig]); } } } If there is interest I will also gladly post the NonPhy script and how to use it.
×
×
  • Create New...