// simple airplane script example //Last edited by Andrew Linden on 12-08-2003 at 02:31 PM // assumes that the root primitive is oriented such that its // local x-axis points toward the nose of the plane, and its // local z-axis points toward the top //if the root primitive of your airplane does not have the same orientation as the whole airplane //(i.e. local x-axis = forward, local y-axis = left, local z-axis = up) then the script will not push //your airplane in the "correct" direction. // //You need to either: // //1. orient your root primitive to agree with the airplane's axes of motion //2. pick a different primitive to be the root (one whose local axes agree with those of the airplane's motion) //3. use the VEHICLE_REFERENCE_FRAME parameter (this is an advanced topic and is outside the scope of a _simple_ airplane script) // control flags that we set later integer gAngularControls = 0; integer gLinearControls = 0; // we keep track of angular history for more responsive turns integer gOldAngularLevel = 0; // the linear motor uses an accumulator model rather than keeping track // of the linear control level history vector gLinearMotor = <0, 0, 0>; default { state_entry() { llSetSitText("Fly"); llCollisionSound("", .0); // the sit and camera placement is very shape dependent // so modify these to suit your vehicle llSitTarget(<.6, .05, .20>, ZERO_ROTATION); llSetCameraEyeOffset(<-10.0, .0, 2> ); llSetCameraAtOffset(<3, .0, 1> ); llSetVehicleType(VEHICLE_TYPE_AIRPLANE); // weak angular deflection llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, .1); llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, 1); // strong linear deflection llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_EFFICIENCY, 1); llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, .2); // somewhat responsive linear motor llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_TIMESCALE, .5); llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, 20); // somewhat responsive angular motor, but with 3 second decay timescale llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_TIMESCALE, .5); llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, 3); // very weak friction llSetVehicleVectorParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, <1000.0, 1000.0, 1000.0> ); llSetVehicleVectorParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, <1000.0, 1000.0, 1000.0> ); llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, .25); // almost wobbly llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 1.5); // mediocre response llSetVehicleFloatParam(VEHICLE_BANKING_EFFICIENCY, .4); // medium strength llSetVehicleFloatParam(VEHICLE_BANKING_TIMESCALE, .1); // very responsive llSetVehicleFloatParam(VEHICLE_BANKING_MIX, .95); // more banking when moving // hover can be better than sliding along the ground during takeoff and landing // but it only works over the terrain (not objects) //llSetVehicleFloatParam(VEHICLE_HOVER_HEIGHT, 3); //llSetVehicleFloatParam(VEHICLE_HOVER_EFFICIENCY, .5); //llSetVehicleFloatParam(VEHICLE_HOVER_TIMESCALE, 2); //llSetVehicleFlags(VEHICLE_FLAG_HOVER_UP_ONLY); // non-zero buoyancy helps the airplane stay up // set to zero if you don't want this crutch llSetVehicleFloatParam(VEHICLE_BUOYANCY, .2); // define these here for convenience later gAngularControls = CONTROL_RIGHT | CONTROL_LEFT | CONTROL_ROT_RIGHT | CONTROL_ROT_LEFT | CONTROL_DOWN | CONTROL_UP; gLinearControls = CONTROL_FWD | CONTROL_BACK; llSetStatus(STATUS_PHYSICS, TRUE); } changed(integer change) { if (change & CHANGED_LINK) { key agent = llAvatarOnSitTarget(); if (agent) { if (agent != llGetOwner()) { // only the owner can use this vehicle llSay(0, "You aren't the owner"); llUnSit(agent); llPushObject(agent, <0,0,10>, ZERO_VECTOR, FALSE); } else { // clear linear motor on successful sit gLinearMotor = <0, 0, 0>; llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, gLinearMotor); //llSetStatus(STATUS_PHYSICS, TRUE); llSetVehicleFloatParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, 1000.0); llSetVehicleFloatParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, 1000.0); llRequestPermissions(agent, PERMISSION_TRIGGER_ANIMATION | PERMISSION_TAKE_CONTROLS); } } else { // stop the motors gLinearMotor = <0, 0, 0>; llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, gLinearMotor); llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, gLinearMotor); // use friction to stop the vehicle rather than pinning it in place //llSetStatus(STATUS_PHYSICS, FALSE); llSetVehicleFloatParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, 1); llSetVehicleFloatParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, 1); // driver is getting up llReleaseControls(); llStopAnimation("motorcycle_sit"); } } } run_time_permissions(integer perm) { if (perm) { llStartAnimation("motorcycle_sit"); llTakeControls(gAngularControls | gLinearControls, TRUE, FALSE); } } control(key id, integer level, integer edge) { // only change linear motor if one of the linear controls are pressed vector motor; integer motor_changed = level & gLinearControls; if (motor_changed) { if(level & CONTROL_FWD) { if (gLinearMotor.x < 0) { gLinearMotor.x = 0; } else if (gLinearMotor.x < 30) { gLinearMotor.x += 5; } motor_changed = TRUE; } if(level & CONTROL_BACK) { if (gLinearMotor.x > 0) { gLinearMotor.x = 0; } else if (gLinearMotor.x > -30) { gLinearMotor.x -= 5; }; motor_changed = TRUE; } llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, gLinearMotor); } // only change angular motor if the angular levels have changed motor_changed = (edge & gOldAngularLevel) + (level & gAngularControls); if (motor_changed) { motor = <0,0,0>; if(level & (CONTROL_RIGHT|CONTROL_ROT_RIGHT)) { // add roll component ==> triggers banking behavior motor.x += 10; } if(level & (CONTROL_LEFT|CONTROL_ROT_LEFT)) { motor.x -= 10; } if(level & (CONTROL_UP)) { // add pitch component ==> causes vehicle lift nose (in local frame) motor.y -= 8; } if(level & (CONTROL_DOWN)) { motor.y += 8; } llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, motor); } // store the angular level history for the next control callback gOldAngularLevel = level & gAngularControls; } }