// RealHeli by Apotheus Silverman // An advanced, semi-realistic helicopter vehicle script for Second Life. // This product is released open source. Please give due credit in // derivative works. :-) // // This behavior script is based on my experience with helicopter flight in // Microsoft Flight Simulator and the included vehicle object is based on // the Hughes 500 model helicopter. // // This vehicle can only be controlled properly in mouselook. // // Helicopter controls: // left/right - tail rotor / rudder // pgup/pgdn - collective // mouse - yoke key currentAgent = NULL_KEY; float minSoundVolume = 0.4; float maxSoundVolume = 1.0; float ROTATION_RATE = 2.0; // Rate of turning float FWD_THRUST = 20; // Forward thrust motor force float BACK_THRUST = 7; // Backup thrust float VERTICAL_THRUST = 7; // Keep a running linear motor value for better response vector linear_motor = <0,0,0>; float collective = 0.0; float oldCollective = 0.0; float myMass; string currentRegion; vector currentVel; vector reference_frame = <0,0,0>; default { state_entry() { llPreloadSound("hughes 500"); llSitTarget(<0.88, 0.0, 0.4>, ZERO_ROTATION); llSetCameraEyeOffset(<-7.0, 0.0, 3.0>); llSetSitText("Fly"); llSetCameraAtOffset(<0, 0, 1>); // Reset flags that can get set from other scripts llSetBuoyancy(0.0); //hover llSetVehicleType(VEHICLE_TYPE_AIRPLANE); llRemoveVehicleFlags(VEHICLE_FLAG_LIMIT_ROLL_ONLY| VEHICLE_FLAG_CAMERA_DECOUPLED); llSetVehicleRotationParam(VEHICLE_REFERENCE_FRAME, llEuler2Rot(reference_frame * DEG_TO_RAD)); llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, 0.9); llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_EFFICIENCY, 0.1); llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, 30); llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 1000); llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_TIMESCALE, 0.5); llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, 0.5); llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_TIMESCALE, 0.1); llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, 120); llSetVehicleVectorParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, <1000,1000,1000>); llSetVehicleVectorParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, <2,2,20>); llSetVehicleFloatParam(VEHICLE_BUOYANCY, 0.0); llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, 0.2); llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 2.0); llSetVehicleFloatParam(VEHICLE_BANKING_EFFICIENCY, 0.0); llSetVehicleFloatParam(VEHICLE_BANKING_MIX, 0.0); llSetVehicleFloatParam(VEHICLE_BANKING_TIMESCALE, 0.05); // Hover mode (mouselook) llRemoveVehicleFlags(VEHICLE_FLAG_MOUSELOOK_STEER) ; llSetVehicleFlags(VEHICLE_FLAG_MOUSELOOK_BANK); llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, <2, 2.5, 0>); } touch_start(integer num) { //llWhisper(0, "Buy me! Right click and choose 'Buy' then take me out of your inventory to fly!"); } 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 of this vehicle."); llUnSit(agent); llPushObject(agent, <0,0,10>, ZERO_VECTOR, FALSE); } else if (currentAgent == NULL_KEY) { // driver is entering the vehicle llSetStatus(STATUS_PHYSICS, TRUE); llRequestPermissions(agent, PERMISSION_TRIGGER_ANIMATION | PERMISSION_TAKE_CONTROLS); currentRegion = llGetRegionName(); currentVel = llGetVel(); llSetTimerEvent(1.0); llMessageLinked(LINK_SET, 1, "hud", NULL_KEY); llLoopSound("hughes 500", minSoundVolume); } } else if (currentAgent) { // driver is getting up currentAgent = NULL_KEY; llStopSound(); llSetStatus(STATUS_PHYSICS, FALSE); llStopAnimation("driving generic"); llReleaseControls(); llSetTimerEvent(0.0); llMessageLinked(LINK_SET, 0, "hud", NULL_KEY); } } } run_time_permissions(integer perm) { if (perm) { currentAgent = llAvatarOnSitTarget(); llStartAnimation("driving generic"); myMass = llGetMass(); collective = 7.3; llTakeControls(CONTROL_FWD | CONTROL_BACK | CONTROL_RIGHT | CONTROL_LEFT | CONTROL_ROT_RIGHT | CONTROL_ROT_LEFT | CONTROL_UP | CONTROL_DOWN, TRUE, FALSE); } } timer() { // Check for and attempt to correct bad sim border crossing string newRegion = llGetRegionName(); if (newRegion != currentRegion) { llApplyImpulse((currentVel - llGetVel()) * myMass, FALSE); currentRegion = newRegion; llSleep(0.2); } // Update VEHICLE_ANGULAR_DEFLECTION_TIMESCALE based on current velocity to simulate drag on the tail currentVel = llGetVel(); float timescale = llVecMag(currentVel) * -0.05 + 0.7; if (timescale < 0.01) { timescale = 0.01; } llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, timescale); // Simulate drag llApplyImpulse(-currentVel * 0.3, FALSE); } control(key id, integer level, integer edge) { if (level & CONTROL_LEFT) { llApplyRotationalImpulse(<0,0,2> * myMass, TRUE); } if (level & CONTROL_RIGHT) { llApplyRotationalImpulse(<0,0,-2> * myMass, TRUE); } if (level & CONTROL_UP) { collective += 0.25; } if (level & CONTROL_DOWN) { collective -= 0.25; } if (oldCollective != collective) { //llWhisper(0, "Collective " + (string)collective); if (llFabs(collective - 9.8) < 0.1) { // Make sure we can always hover collective = 9.8; } if (collective > 12.8) { collective = 12.8; } else if (collective < 7.3) { collective = 7.3; } llSetForce(<0, 0, collective> * llGetMass(), TRUE); llMessageLinked(LINK_SET, (integer)(((collective - 7.3) / 5.5) * 100.0), "throttle", NULL_KEY); llAdjustSoundVolume(((collective - 7.3) / 5.5) * (maxSoundVolume - minSoundVolume) + minSoundVolume); } oldCollective = collective; } }