Join us in Phaze Demesnes

LSL Script Library Home   Add a script Show All
Category: Contributor: Description
Vehicles Fritz Kakapo Li'l Stinker, a better approach to sl flight
This script represents the current state of the art of adapting the SL physics engine to implement a standard simple linearized model of the flight of an airplane.
This script represents the current state of the art of adapting the SL physics engine to implement a standard simple linearized model of the flight of an airplane.  As far a the author knows, this is the only real attempt by an sl scripter to model the forces on a flying body.  Other flight scripts (except derivatives of this one) start from a generic sl vehicle and add airplane-like features such as banking and a minimum flight speed, an approach that will not lead to realistic flight without endless correction.
I did not realize, when I started, that this was unique, but, in hindsight, it would be very unlikely for anyone else working on airplane flight scripts, or for Linden Laboratories, to have anywhere near the same preparation for this sort of project that I have.  I am only an educated amateur with airplanes, but my education and experience with physical modeling and numerical methods is about as good as anyone's.  So far it appears that I may have been using my effort and my wonderful education for my own amusement.  Only my parrot has become popular, and that may be mainly because of the nice picture I found for the textures and because it is free.  Most of the established builders and pilots seem quite happy to fly level with their wings vertical.  They are naturally resistant to starting over.  But, as new people come along, some may choose to do things this way, and this may become a valuable teaching opportunity.
This script is still distributed under a GNU Free Public License, but, in case the copyright covers more than I realize, I specifically grant permission to use the methods and short sections of this script in proprietary scripts.  Direct derivatives, on the other hand, can be used in proprietary airplanes, but the derived scripts must be distributed in editable form, in some way.
This script has a lot of extras to negotiate sim crossings, change flight modes, etc., so I recommend starting with my Air Camper script (also posted here) and using this script as a reference for adding features.

Download this script - Please use this link to get this script. If you see all the code on one long line, please use Wordpad or another editor, such as LSLEdit.exe. The .LSL file you will download is an ordinary text file.

1 // Li'l Stinker Flight Script, by Fritz t. Cat (Fritz Kakapo)
2 //
3 // Since the version I started with was public domain, with free software intentions expressed,
4 // I, Fritz t. Cat, hereby publish my modified version, below, under the GNU General Public License,
5 // on 2009 July 14 and subsequent versions as available. This means that it is a copyright violation to set
6 // no-copy, no-modify, no-transfer or turn off "allow anyone to copy" on this script,
7 // the Li'l Stinker Airplane for which it was written, or anything derived from either of them.
8 // And also that a GNU Licence statement and credits, according to the current version of the license,
9 // must accompany anything derived from this script or airplane. I have reproduced the public domain script,
10 // in a note card, for use in proprietary products.
11 // Airplanes with scripts derived from this one need to be sold or given along with a copy of the same code version
12 // as is in the airplane. Derived airplanes with other scripts need to be full permissions or distributed
13 // along with a full permissions version, but the unrelated script need not be copyable.
14 // The aerodynamics and algorithms uses are not copyrightable and may be freely used as a guide to other scripts.
15 // Please refer to some source, such as Wikipedia, for the exact license terms.
16 //
17 // I have kept some of the earlier comments here:
18 //"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
19 // Simple airplane script example
20 // THIS SCRIPT IS PUBLIC DOMAIN! Do not delete the credits at the top of this script!
21 // Nov 25, 2003 - created by Andrew Linden and posted in the Second Life scripting forum
22 // Jan 05, 2004 - Cubey Terra - minor changes: customized controls, added enable/disable physics events
23 // Feel free to copy, modify, and use this script.
24 // Always give credit to Andrew Linden and all people who modify it in a read me or in the object description.
25 //"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
26 //
27 // See the accompanying note card for operating instructions. <-----------------------------------------<<<<
28 //
29 //"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
30 //
31 // The VICE is taken from "Flight Script EEv3 (VICE 1.2.0)" and "VICE ALA Test Airplane v. 1.2.0".
32 //
33 //"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
34 //
35 // Since virtual materials are cheap, I am using carbon nanotubes for most of the structure,
36 // so this airplane is very light!
37 // (Alos other carbon forms and other materials not easily obtained in rl.
38 // The piston rings are osmium boride. Diamond is used extensively in the engine,
39 // because of its good heat conductivity.)
40 //
41 // The script assumes that the root primitive is oriented such that its:
42 // local x-axis points toward the nose of the plane, and its
43 // local z-axis points toward the top.
44 //
45 // Lift is proportional to the square of the speed, like centrifugal force, so (excluding structural failure)
46 // an airplane can turn in the same radius at high speed as at low speed, unlike a car. (Actually perhaps
47 // somewhat smaller, due to Reynolds number effects.) Without correction, the lift here due to turning the velocity
48 // is only proportional to the speed. Though still better than a car, that is not fully realistic or fun.
49 // If this were corrected, one could learn a maneuver and then keep doing it faster, as long as the simulator
50 // could support the speed and acceleration. This has partially been done in the timer routine near the end.
51 //
52 // The physics engine that applies the forces controled by the VEHICLE parameters appears to run at
53 // about 40 frames per second. These functions include lift and drag, as well as applying the torqes and damping
54 // set in timer, and calculation of the resulting rotation and motion. The controls are done with abrupt torques,
55 // so the time scale is that of the arrow key input, like ordinary SL movement and flying. An instantaneous torque is
56 // about the same response speed as simple mechanically operated control surfaces.
57 // The dynamic coupling and trim added, to make it really fly like an
58 // airplane, instead of like a generalized vehicle that flies and banks, runs in timer. The time interrupt
59 // rate is set for 0.5 sec., and the script tries to conpensate for slow response by slowing down.
60 //
61 //-----------------------------------------------------------------------------------------------------------------------------------
62 //
63 // Free VICE airplane script credits:
64 // This airplane is a freebie; it includes a modified freebie flight script (EEV3) designed to support VICE
65 // In VICE terms, this airplane is an ALA with 2 LMG guns (contained in the gun prims, naturally)
66 // This VICE mod is by Creem Pye, April 1 2008
67 // Special thanks to Xenox Snook for supplying the fuselage!
68 // All the other people credited below worked on the airplane script, as far as I know...
69 //
70 // Modified from Cubey Terra DIY Plane 1.0 by Eoin Widget and Kerian Bunin
71 // which was originaly marked as September 10, 2005
72 // Distribute freely. Go ahead and modify it for your own uses. Improve it and share it around.
73 // Some portions based on the Linden airplane script originall posted in the forums.
74 // ** Last Modified by Eoin Widget on March 26, 2006 **
75 //
76 //===================================================================================================================================
77 //
78 //
79 // control flags that we set later
80 integer gAngularControls = 0;
81 integer gLinearControls = 0;
82 //
83 // The propeller thrust is saved and restored as it decays, to continue cruising.
84 vector gLinearMotor = < 0, 0, 0 >;
85 //
86 float last_time = 99999999.; // previously stored time of day
87 integer sit = FALSE; // keeps track of whether flying or parked
88 integer motor_idle = TRUE; // Motor has been set to zero speed by touching the airplane.
89 //
90 float torque_factor = 1.; // Used to increase control effectiveness with speed.
91 //
92 vector steady_torque = < 0, 0, 0. >; // Aerodynamic dynamic torque, independant of controls.
93 //
94 float LINEAR_MOTOR_TIMESCALE_0 = 2.; // 1/strength when going slow
95 //
96 float ANGULAR_MOTOR_TIMESCALE_0 = 2.5 ; // 1/strength. Damping and dynamic torque.
97 //
98 vector LINEAR_FRICTION_TIMESCALE_0 = < 30., 4., 0.50 >;
99 //
100 vector ANGULAR_FRICTION_TIMESCALE_0 = < 2.5, 2.5, 7.5 >; // Along with angular motor time scale,
101 //
102 float speed = 0.;
103 float maxThrottle = 45;
104 float timer_dialation = 1.; // Slow down when lag is bad.
105 float o_t_d = 1.; // previous value of slow down
106 float energy = 1.; // From the physics engine.
107 //
108 float mass;
109 float mass_factor = 1.; // Adapt to a particular airplane.
110 float buoyancy = 0.3; // buoyancy for no lag, depends on touring or advanced mode
111 //
112 integer listenHandle;
113 integer homing = FALSE; // Try to stay in si
114 //
115 key pilot=NULL_KEY;
116 //
117 integer edges = 0;
118 integer levels = 0;
119 //
120 integer updating = FALSE;
121 integer kownt_3; // time since last control entry
122 //
123 //-----------------------------------------------------------------------------------------------------------------------------------
124 integer HUDon = TRUE;
125 string HUDtext="";
126 vector HUDcolor;
127 vector local_vel;
128 //===================================================================================================================================
129 //
130 //
131 // This is called whenever there is flight control input, from timer, from control, from listen and from touch_start.
132 Update()
133 {
134 if ( updating ) jump GOTO; // Skip possible reentrant call, if possible in this system.
135 updating = TRUE;
136 //
138 speed = llSqrt( v * v );
139 //
140 //----------------------------------------------- Handle Exceptions, Environment-----------------------------------------------------
141 //
142 // Slow down for lag. Pause if too bad.
143 float time = llGetTimeOfDay();
144 float time_interval = time - last_time;
145 if ( time_interval <= 0. ) time_interval = 0.5; // Fix bad times.
146 last_time = time;
147 //
148 float lag = 1. / llSqrt( time_interval*time_interval + 1. ); // << 1 = laggy, otherwize near 1.
149 //
150 if ( lag < timer_dialation )
151 { timer_dialation = lag; } // Take new lag if worse.
152 else
153 { timer_dialation = timer_dialation * 0.5 + lag * 0.5; } // Else smooth out a bit.
154 //
155 vector pos = llGetPos();
156 //
157 if ( pos.x < -1. || pos.x > 257. ) { timer_dialation = timer_dialation*0.4; }
158 // Slow for delayed handover or other problem.
159 if ( pos.y < -1. || pos.y > 257. ) { timer_dialation = timer_dialation*0.4; } // But continue along end of world.
160 if ( pos.z < -1. ) { timer_dialation = timer_dialation*0.4; }
161 if ( pos.z > 4000. )
162 {
163 llApplyImpulse( < -100., 0, -40. >, TRUE ); // Push back and down to stay on world.
164 llApplyRotationalImpulse( < 1.7, 1.7, -1.7 >, TRUE );
165 gLinearMotor = gLinearMotor*0.97;
166 llWhisper(0, "Altitude ceiling reached." );
167 } // But not top.
168 //
169 if ( timer_dialation < 0.3 && timer_dialation < o_t_d ) { llWhisper(0, "Slowed to " + (string)timer_dialation + " for lag."); }
170 o_t_d = timer_dialation;
171 //
172 // Now look if we are approaching edge of sim.
173 vector projected = pos + v*time_interval*1.5; // engeneering margin
174 //
175 if( projected.x < 0. || projected.x > 256. )
176 {
177 if( llEdgeOfWorld( pos, < v.x, 0, 0 > ) )
178 {
179 // I want to turn away from the edge, but that is not simple.
180 // Can't set the speed, have to apply a force or impulse away from edge of world.
181 }
182 else // Expect sim crossing before next entry.
183 {
184 timer_dialation = timer_dialation * 0.2; // Slow down for crossing.
185 }
186 }
187 if( projected.y < 0. || projected.y > 256. )
188 {
189 if( llEdgeOfWorld( pos, < v.y, 0, 0 > ) )
190 {
191 // I want to turn away from the edge, but that is not simple.
192 // Can't set the speed, have to apply a force or impulse away from edge of world.
193 }
194 else // Expect sim crossing before next entry.
195 {
196 timer_dialation = timer_dialation * 0.2; // Slow down for crossing.
197 }
198 }
199 //
200 //
201 llSetVehicleVectorParam( VEHICLE_ANGULAR_FRICTION_TIMESCALE, ANGULAR_FRICTION_TIMESCALE_0 * timer_dialation );
202 //
203 llSetVehicleFloatParam( VEHICLE_BUOYANCY, 1. - timer_dialation*(1.-buoyancy) );
204 //
205 llSetVehicleVectorParam( VEHICLE_LINEAR_FRICTION_TIMESCALE, LINEAR_FRICTION_TIMESCALE_0 * timer_dialation / (speed+0.0005) );
206 //
207 if ( time_interval > 20. * (1.+buoyancy) )
208 { llSetStatus(STATUS_PHYSICS, FALSE); llWhisper( 0, "Flight suspended, for timeout. Click to resume." ); }
209 // Turn off physics. Wait for user to be able to touch aircraft, showing that a simulator has them back together.
210 // Usually when crossing sim boundaries.
211 //
212 // See if the simulator thinks we have been too busy.
213 energy = energy * 0.75 + llGetEnergy() * 0.25; // Smooth over sim crossings.
214 if ( energy < 0.45 )
215 {
216 llWhisper( 0, "Energy reduced to" + (string)energy );
217 //
218 if ( energy < 0.2 )
219 { llSetStatus(STATUS_PHYSICS, FALSE); llWhisper( 0, "Flight suspended, to let the engine cool." ); } // Pause physics.
220 }
221 // End Exeptions.
222 //
223 //-------------------------Include speed increase of contol surface effectiveness. --------------------------
224 //
225 torque_factor = ( 0.15 + 40. * speed/8. * speed/8. ) * mass_factor * timer_dialation * (1.-buoyancy) * (1.-buoyancy);
226 //
227 llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_TIMESCALE, ANGULAR_MOTOR_TIMESCALE_0 / torque_factor );
228 //
229 //-------------------------------------------------------------------------------------------------------------------------------
230 steady_torque = < 0., 0, 0. >; // Start with no turn.
231 //
232 //---------------------------------------------------- Control ----------------------------------------------------------------
233 //
234 // only change linear motor if one or more of the linear controls is pressed, and only once
235 if ( edges & levels & gLinearControls )
236 {
237 //
238 if ( edges & levels & CONTROL_UP )
239 {
240 if ( gLinearMotor.x < maxThrottle ) // "Damped to about 30." Over 30 to cover drag.
241 gLinearMotor.x += 3.;
242 }
243 if ( edges & levels & CONTROL_DOWN )
244 {
245 if ( gLinearMotor.x > -maxThrottle/3. )
246 gLinearMotor.x -= 3.;
247 }
248 //
249 if ( levels & CONTROL_DOWN && levels & CONTROL_UP )
250 {
252 {
253 llSetStatus( STATUS_PHYSICS, TRUE ); // Resume flight, under pilot control.
254 llWhisper( 0, "Flight resumed." );
255 }
256 else
257 {
258 if ( motor_idle )
259 {
261 llWhisper( 0, "Flight suspended, manually." );
262 }
263 else
264 {
265 gLinearMotor = <0,0,0>; // Stop the engine.
266 motor_idle = TRUE;
267 llWhisper( 0, "Throttle closed." );
268 }
269 }
270 }
271 else
272 {
273 motor_idle = FALSE;
274 }
275 //
276 float power = llSqrt( gLinearMotor * gLinearMotor + 0.1 );
277 llSetVehicleFloatParam( VEHICLE_LINEAR_MOTOR_TIMESCALE, LINEAR_MOTOR_TIMESCALE_0 / llSqrt(power) * 3. );
278 // 1/strength
279 } // End Linear.
280 //
281 // Angular Controles
282 // Changed to impulse angular control, but F. t. C.,
283 // for the faster response of a stunt plane.
284 //
285 if ( levels & gAngularControls )
286 {
287 vector impulse_torque = <0,0,0>;
288 //
289 // Aileron roll control:
290 if ( levels & CONTROL_ROT_LEFT )
291 {
292 if ( edges & CONTROL_ROT_RIGHT && buoyancy == 0. )
293 impulse_torque.x -= 1.0 * torque_factor;
294 //
295 steady_torque.x -= 0.7;
296 }
297 if ( levels & CONTROL_ROT_RIGHT )
298 {
299 if ( edges & CONTROL_ROT_RIGHT && buoyancy == 0. )
300 impulse_torque.x += 1.0 * torque_factor;
301 //
302 steady_torque.x += 0.7;
303 }
304 //
305 // Pitch component, elevator ==> causes vehicle lift nose (in local frame):
306 if ( levels & CONTROL_BACK )
307 {
308 if ( edges & CONTROL_BACK && buoyancy == 0. ) // up
309 impulse_torque.y -= 0.7 * torque_factor;
310 //
311 steady_torque.y -= 0.5;
312 }
313 if ( levels & CONTROL_FWD ) // down
314 {
315 if ( edges & CONTROL_FWD && buoyancy == 0. )
316 impulse_torque.y += 0.7 * torque_factor;
317 //
318 steady_torque.y += 0.5;
319 }
320 //
321 // Rudder control:
322 if ( levels & CONTROL_RIGHT )
323 {
324 if ( edges & CONTROL_RIGHT && buoyancy == 0. )
325 impulse_torque.z -= 0.7 * torque_factor;
326 //
327 steady_torque.z -= 0.5;
328 }
329 if ( levels & CONTROL_LEFT )
330 {
331 if ( edges & CONTROL_LEFT && buoyancy == 0. )
332 impulse_torque.z += 0.7 * torque_factor;
333 //
334 steady_torque.z += 0.5;
335 }
336 //if ( speed < 1.0 ) { impulse_torque = 5. * impulse_torque; } // Effective turn on ground.
337 //
338 llApplyRotationalImpulse( impulse_torque, TRUE );
339 //
340 edges = 0; // We only respond to these once.
341 } // End angular contols.
342 // End Control.
343 //
344 //----------------------------------- Routine Flight --------------------------------------------------------------------------
345 //-------------------------------------- Refresh motor settings. ------------------------------------------
346 //
348 // This is to defeat VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE.
349 //
350 //
351 local_vel = v / llGetRot(); // global to local coordines
352 //llWhisper(0, (string)local_vel );
353 //
354 //------------------------------------Stear Toward Regeon Center.----------------------------------------------
355 //
356 if ( homing )
357 {
358 // This is not realistic for a piloted airplane, but it helps avoid sim boundaries.
359 // It is more like the Cox control line Little Stinker that flies constrained to a hemeshere.
360 //
361 vector toCenter = ( < 128, 128, 0 > - pos ); // global vector to center of sim
362 // This is the locaiton that it flies around.
363 //
364 // Roll and yaw to the port of center, moving inward and to starboard when moving away from center.
365 // This moves it toward center, when circling right.
366 vector h_toCenter = toCenter;
367 h_toCenter.z = 0; // No vertical here.
368 vector loc_h_toCenter = h_toCenter / llGetRot(); // global to local coordinate transformation;
369 vector left = -loc_h_toCenter * (local_vel.x/5.) * 0.00010;
370 left.y = 0; // No pitch.
371 left.z = -10 * left.x; // Roll component goes to roll and yaw.
372 steady_torque += left; // Roll to left of center, to right away.
373 //
374 // Turn toward center. This tends to move it to center when not circeling.
375 vector turn_toCenter = < 1, 0, 0 > % loc_h_toCenter * (local_vel.x/5.) * 0.0004;
376 // Forward x [vector cross product] radius = torque toward center. Adjust strength.
377 steady_torque += turn_toCenter; // Add to torque.
378 }
379 //
380 //
381 //
382 //--------------------------- Dynamic Coupling and Trim Tuning -----------------------------------------------
383 //
384 if ( homing )
385 {
386 // Spiral right to help stay in sim. Physically, this comes from the left hand propeller rotation.
387 float right = 0.0; // (English and American propellers usually rotate like a right
388 right += -local_vel.z * 0.010; // hand screw, but old German and Swiss engines ran the other way.)
389 steady_torque.x += right;
390 steady_torque.z -= 2.3 * right;
391 }
392 //
393 // Dihedral: Wing tip on the downward side lifts when moving sideways.
394 steady_torque.x += 0.05 * local_vel.y;
395 //
396 // Wing sweep action: side slip times lift turns roll back up.
397 // The down side wing has more lift, but only if it is already lifting.
398 steady_torque.x -= 0.04 * ( local_vel.y * local_vel.z );
399 //
400 //
401 // Turn upward: This is the trim incidence of the stabalizer. Global down when up side down.
402 if ( homing )
403 {
404 steady_torque.y -= 0.025 * local_vel.x/5. * (1.-buoyancy) * llSqrt(1.-buoyancy);
405 }
406 //
407 // Turn upward: I don't know how to do this in rl with a passive shape. Remains global up when up side down.
408 steady_torque.y += 0.004 * local_vel.x/5. * local_vel.z * (1.-buoyancy) * llSqrt(1.-buoyancy);
409 //
410 // Turn up.
411 steady_torque.y += 0.05 * local_vel.z * (1.-buoyancy) * llSqrt(1.-buoyancy);
412 //
413 //
415 refreshHUD();
416 //
417 updating = FALSE;
418 @ GOTO;
419 } // End Update.----------------------------------------------------------------------------------
420 //
421 //-----------------------------------------------------------------------------------------------------------------------------------
422 //
423 refreshHUD()
424 {
425 if ( !sit )
426 {
427 HUDtext="Take a copy. \n Full permissions.
428 New aerodynamic flight script 4.0 .
429 Open the airplane as a box to get the documentation.";
430 HUDcolor = < 0.2, 0.4, 1. >;
431 jump early_exit;
432 }
433 //
434 if ( !HUDon )
435 {
436 llSetText( "", <0,0,0>, 0. );
437 jump early_exit;
438 }
439 //
440 float fwd = gLinearMotor.x;
441 //
442 HUDtext="Airpeed: "+(string)llFloor((local_vel.x+0.5)) + " m/sec. = "+(string)llFloor((local_vel.x*1.94+0.5)) + " kts.
443 Throttle: "+(string)llFloor(fwd*100.0/maxThrottle)+"%";
444 HUDcolor=<1.0,1.0,1.0>; // white when combat is disabled
445 //
446 @early_exit;
447 //
448 llSetText( "", HUDcolor, 1.0);
449 //llSetText(HUDtext+"\n \n \n \n \n \n \n ", HUDcolor, 1.0);
450 //
451 llMessageLinked( 2, 25*(integer)(HUDcolor.x*4.)
452 + 5*(integer)(HUDcolor.y*4.)
453 + (integer)(HUDcolor.z*4.), "HUDcolor", NULL_KEY );
454 llMessageLinked( 2, 137, HUDtext+"\n \n \n \n \n \n \n \n ", NULL_KEY );
455 //
456 } // End refreshHUD().
457 //
458 //-----------------------------------------------------------------------------------------------------------------------------------
459 default
460 {
462 {
463 llSetSitText( "Fly" );
464 //llCollisionSound( "", 0.0 );
465
466
467
468 // the sit and camera placement is very shape dependent
469 // so modify these to suit your vehicle
470 llSitTarget( < 0.35, 0.0, 0.33 >, ZERO_ROTATION); // pilot position, relative to root
471 //
472 llSetCameraEyeOffset( < -11.5, 0.0, 4.5 > ); // location of camera, relative to vehicle
473 llSetCameraAtOffset( < 0.0, 0.0, 2.4 > ); // focus point of camera, " "
474 //
475 //---------------------------------------------------------------------------------------------------------------------------
476 //
477 llSetVehicleType( VEHICLE_TYPE_AIRPLANE ); // Sets default airplane-like parameters.
478
479
480
481 // action of the fin and stabilizer: Points toward velocity.
482 // The front turns toward the current velocity.
483 llSetVehicleFloatParam( VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, 1. ); // "behave much like the deflection time scales"
485 //
486 // Fuselage lift. Wing lift is handled with VEHICLE_LINEAR_FRICTION_TIMESCALE below.
487 // The velocity turns toward the front. (Exact formula unknown.)
488 llSetVehicleFloatParam( VEHICLE_LINEAR_DEFLECTION_EFFICIENCY, 1.0 ); // "behave much like the deflection time scales"
490 //
491 // propeller thrust strength
492 // Shorter time scale makes it more stable. Longer makes it more physical (aerodynamic). Too long makes it hard to move.
493 llSetVehicleFloatParam( VEHICLE_LINEAR_MOTOR_TIMESCALE, LINEAR_MOTOR_TIMESCALE_0 ); // 1/strength
494 // "it cannot be set longer than 120 seconds"
495 llSetVehicleFloatParam( VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, 5.); // Throttle gradually closes with time but defeated:
496 // Refreshed below in timer.
497 //
498 // control surfaces, ailerons, elevators (and maybe later rudder)
499 llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_TIMESCALE, ANGULAR_MOTOR_TIMESCALE_0 ); // 1/strength
500 llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, 5. ); // Control returns to neutral when released.
501 //
502 //--------------------- linear friction ------------------------------------------------
503 // The x component is parasite drag (along with VEHICLE_LINEAR_MOTOR_TIMESCALE).
504 // The y component contributes to fuselage transverse lift and to drag due to yaw.
505 // The z component might seem to be just a vertical damping, but when pitch changes by a small amount,
506 // most of the motion in the direction that was previously forward, becomes motion in the new forward direction,
507 // with initially only a small transverse (up or down) component. With a short decay time scale
508 // in the z direction, that component is lost quickly, so the motion continues to follow the pitch angle.
509 // The larger the z time constant is, the more "induced drag" there is. That is VEHICLE_LINEAR_FRICTION_TIMESCALE.z
510 // greater than zero causes a drag that increases with lift, similarly to induced drag of a physical airplane.
511 //
512 // The z component gives the wing lift. Decreasing it allows the airplane to fly more slowly,
513 // without loss of speed or altitude. But it seems to be near the limit, to fly much slower one may need buoyancy.
514 llSetVehicleVectorParam( VEHICLE_LINEAR_FRICTION_TIMESCALE, LINEAR_FRICTION_TIMESCALE_0 );
515 //
516 llSetVehicleVectorParam( VEHICLE_ANGULAR_FRICTION_TIMESCALE, < 0.25, 0.5, 0.5 > ); // Along with angular motor time scale,
517 // This damps the rotational motion.
518 //
519 llSetVehicleFloatParam( VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 1000 ); // CG below center of lift, pendulum period.
520 llSetVehicleFloatParam( VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, 0 ); // damping, 0–1: 1. is fully damped.
521 // This needs to be weak for a stunt airplane, that should fly nearly the same upside down as right side up.
522 // It is desirable especially in free flight models, such as paper gliders. See the dynamic coupling in timer.
523 //
524 // This drives yaw in the direction of roll, imitating use of rudder by the pilot.
525 llSetVehicleFloatParam( VEHICLE_BANKING_EFFICIENCY, 0 ); // Is there a difference between time scale
526 llSetVehicleFloatParam( VEHICLE_BANKING_TIMESCALE, 1000 ); // and efficiency?
527 llSetVehicleFloatParam( VEHICLE_BANKING_MIX, 0 ); // more yaw control when moving, 0 = none at rest.
528 // Since this imitates a manual control, any convenient value set is physical (assuming a rotating tail wheel).
529 // The Wright brothers found that mechanical coupling of the rudder and ailerons was not sufficient,
530 // because of the delays involved.
531 // It is not used here, because it was not intended for attitudes far from right side up.
532 //
533 // "hover can be better than sliding along the ground during takeoff and landing
534 // but it only works over the terrain (not objects)"
539 //
540 // "non-zero buoyancy helps the airplane stay up
541 // set to zero if you don't want this crutch"
542 // This was useful in the initial stages of tuning. I think it simply reduces the gravitational
543 // contribution to downward acceleration. Try this to make it easier to fly.
545 //
546 // define these here for convenience later
547 // CUBEY - modified these as per Shadow's prefs
549 gLinearControls = CONTROL_UP | CONTROL_DOWN; // These control the engine throttle.
550 //
551 llSetStatus( STATUS_PHYSICS, FALSE ); //CUBEY - ensure that physics are disabled when plane is rezzed so it doesn't fly off
552 sit = FALSE; // Keep track of not flying.
553 //
554 mass = llGetMass();
555 mass_factor = (mass/12.5) * llSqrt( llSqrt(mass/12.5) );
556 //llSay(0, (string)mass+" virtual kilograms." );
557 llSay(0, "Ready to wash." );
558 refreshHUD();
559 //
560 } // End state_entry()
561 //-----------------------------------------------------------------------------------------------------------------------------------
562 //
563 // DETECT AV SITTING/UNSITTING AND TAKE CONTROLS
564 //-----------------------------------------------------------------------------------------------------------------------------------
565 changed(integer change)
566 {
567 if ( change & CHANGED_LINK )
568 {
569 pilot = llAvatarOnSitTarget();
570 if (pilot)
571 {
572 if (pilot != llGetOwner())
573 //if ( FALSE )
574 {
575 // only the owner can use this vehicle
576 llWhisper(0,
577 "Please take a copy of this airplane and fly your own copy.
578 (If it is not set \"free to copy\" or \"for sale 0 l$\" contact the owner or the creator.)
579 You aren't the owner -- only the owner can fly this plane.");
580 llUnSit(pilot);
581 //llPushObject(pilot, <0,0,10>, ZERO_VECTOR, FALSE);
582 }
583 else
584 { // Pilot sits on vehicle
585 // Clear linear motor on successful sit.
586 //llTriggerSound("cbb7a77f-4302-e3b3-4c1f-6dcb30bf3382",1.0); // engine startup
587 //sit = TRUE;
588 //onGround=TRUE;
589 llMessageLinked(LINK_SET, TRUE, "seated", pilot);
591 listenHandle = llListen( 0, "", pilot, "" );
592 }
593 }
594 else if ( sit )
595 // When changed is called with flying and CHANGED_LINK, it is usually that the avatar is getting up.
596 {
597 // Pilot is getting up.
598 llWhisper(0, "Ignition off.");
599 llMessageLinked(LINK_SET, FALSE, "seated", "");
600 //
601 // Stop the works.
602 llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_TIMESCALE, 2. ); // Allow it to rotate when it touches.
604 llSetVehicleVectorParam( VEHICLE_LINEAR_MOTOR_DIRECTION, <0,0,0> ); // Turn off engine.
605 llSetVehicleFloatParam( VEHICLE_BUOYANCY, 0.0 ); // Allow it to fall or fly.
606 //
607 // Let friction slow the vehicle rather than pinning it in place.
608 //
610 llStopAnimation("sit");
611 //
612 llSleep( 8. ); // Wait for it to stop.
613 //
614 llSetStatus( STATUS_PHYSICS, FALSE ); //Turn off "physics" to make sure the parked plane not be move.
615 sit = FALSE; // Keep track of whether sitting.
616 llSetTimerEvent( 0 ); // Stop timer.
617 llWhisper(0, "Brake set.");
618 refreshHUD();
619 //
620 }
621 }
622 } // End changed.
623 //-------------------------------------------------------------------------------------------------
625 {
626 if (perm)
627 {
628 llStartAnimation("sit");
629 llTakeControls( gAngularControls | gLinearControls | CONTROL_LBUTTON, TRUE, FALSE );
630 gLinearMotor = < 0., 0., 0. >;
633 llSetStatus( STATUS_PHYSICS, TRUE ); //CUBEY - enable physics when avatar sits
634 sit = TRUE; // Keep track of whether flying or not.
635 //
636 llSetTimerEvent( 0.25 ); // seconds This is to refresh forces and torques that have decayed.
637 // Also dynamic coupling, etc.
638 last_time = llGetTimeOfDay(); // Here the script starts do it own "real" time. Initially only to tell when
639 // things are so bad we'd better pause the animation.
640 kownt_3 = 0;
641 llWhisper(0, "
642 Engine started.
643
644 Arrow keys -- up, down, roll right, left.
645 Shift with arrow keys works the rudder.
646 Flight modes are \"t\", \"n\" and \"e\".
647 \"s\" to toggle stear to stay in sim.");
648 //
649 //
650 }
651 }
652 //FLIGHT CONTROLS
653 //-----------------------------------------------------------------------------------------------------------------------------------
654 control( key id, integer control_levels, integer control_edges )
655 {
656 edges = control_edges;
657 levels = control_levels;
658 //
659 Update(); // Do everything.
660 //
661 kownt_3 = 0; // time since last control entry
662 } // End control.
663 // (The controls really aught to reverse when going backwards,
664 // but it seems convienient to be able to turn on the ground.)
665 //===============================================================================================================================
666 //
667 //
668 listen( integer channel, string name, key id, string message )
669 {
670 //
671 if ( message == "hud on" || message == "HUD ON" ) // expert mode
672 {
673 HUDon = TRUE;
674 refreshHUD();
675 }
676 //
677 if ( message == "hud off" || message == "HUD OFF" ) // expert mode
678 {
679 HUDon = FALSE;
680 refreshHUD();
681 }
682 //---------------------------------------------------------------------------------------------------------------------------
683 //
684 if ( message == "e" || message == "E" ) // expert mode
685 {
686 buoyancy = 0.;
687 llWhisper(0, "Expert mode set." );
688 }
689 else if ( message == "n" || message == "N" ) // normal mode
690 {
691 buoyancy = 0.4;
692 llWhisper(0, "Normal mode set." );
693 }
694 else if ( message == "t" || message == "T" ) // touring mode
695 {
696 buoyancy = 0.6;
697 homing = FALSE;
698 llWhisper(0, "Touring mode set." );
699 }
700 else if ( message == "s" || message == "S" ) // Stay on sim on, off.
701 {
702 if ( homing )
703 {
704 homing = FALSE;
705 llWhisper(0, "Stear around sim center off." );
706 }
707 else
708 {
709 homing = TRUE;
710 llWhisper(0, "Stear around sim center on." );
711 }
712 }
713 //
714 //
715 Update(); // Periodic tasks
716 } // End listen.
717 //
718 //===============================================================================================================================
719 timer() // Added by F. t. C.
720 {
721 Update(); // Periodic tasks
722 //
723 // If timer is running but there has been no control recently, then the airplane must be lost,
724 // unless the auto-pilot is on.
725 if ( kownt_3 == 2*60*4 && !homing )
726 {
728 kownt_3 = -2*60*60*4; // how long till next IM
729 }
730 //llOwnerSay( (string)kownt_3 );
731 kownt_3 += 1; // time since last control entry
732 //
733 }// End timer.
734 //
735 //===============================================================================================================================
736 touch_start(integer total_number)
737 {
738 if ( sit )
739 {
741 {
742 llSetStatus( STATUS_PHYSICS, TRUE ); // Resume flight, under pilot control.
743 llWhisper( 0, "Flight resumed." );
744 }
745 else
746 {
747 if ( motor_idle )
748 {
750 llWhisper( 0, "Flight suspended, manually." );
751 }
752 else
753 {
754 gLinearMotor = <0,0,0>; // Stop the engine.
755 motor_idle = TRUE;
756 llWhisper( 0, "Throttle closed." );
757 }
758 }
759 }
760 //
761 Update(); //-------- Handle Exceptions, Environment----------------------------------------------
762 }
763 } // End default.
764 //
765 // (The controls really aught to reverse when going backwards,
766 // but it seems convienient to be able to turn on the ground.)