Nil fix
[fg:toms-fgdata.git] / Aircraft / Buccaneer / Nasal / buccaneer-utils.nas
1 #####################################################################################
2 #                                                                                   #
3 #  this script contains a number of utilities for use with the Buccaneer (YASim fdm)    #
4 #                                                                                   #
5 #####################################################################################
6
7 # ================================ Initalize ====================================== 
8 # Make sure all needed properties are present and accounted 
9 # for, and that they have sane default values.
10
11 view_number_Node = props.globals.getNode("sim/current-view/view-number",1);
12 view_number_Node.setDoubleValue(0);
13
14 view_name_Node = props.globals.getNode("sim/current-view/name",1);
15 view_internal_Node = props.globals.getNode("sim/current-view/internal",1);
16 view_internal_Node.setBoolValue(1);
17
18 enabledNode = props.globals.getNode("sim/headshake/enabled", 1);
19 enabledNode.setBoolValue(1);
20
21 rainingNode = props.globals.getNode("sim/model/buccaneer/raining", 1);
22 rainingNode.setValue(0);
23
24 precipitationenabledNode = props.globals.getNode("sim/rendering/precipitation-aircraft-enable", 1);
25 precipitationenabledNode.setBoolValue(0);
26
27 precipitationcontrolNode = props.globals.getNode("sim/rendering/precipitation-gui-enable", 1);
28 precipitationcontrolNode.setBoolValue(0);
29
30 n1_node = props.globals.getNode("engines/engine/n1", 1);
31 smoke_node = props.globals.getNode("engines/engine/smoking", 1);
32 smoke_node.setBoolValue(1);
33
34 fuel_dump_lever_Node = props.globals.getNode("controls/fuel/dump-valve-lever", 1);
35 fuel_dump_lever_Node.setDoubleValue(0);
36 fuel_dump_lever_pos_Node = props.globals.getNode("controls/fuel/dump-valve-lever-pos", 1);
37 fuel_dump_lever_pos_Node.setDoubleValue(0);
38 fuel_dump_Node = props.globals.getNode("controls/fuel/dump-valve", 1);
39 fuel_dump_lever_Node.setBoolValue(0);
40
41 for(var i = 0; i < 3; i = i + 1){
42     setprop("/sim/model/formation/position[" ~ i ~ "]/x-offset", 0);
43     setprop("/sim/model/formation/position[" ~ i ~ "]/y-offset", 0);
44     setprop("/sim/model/formation/position[" ~ i ~ "]/z-offset", 0);
45 }
46
47 setprop("/controls/autoflight/autopilot/ico", 0);
48 setprop("sim/alarms/gear-up", 0);
49 setprop("velocities/mach",0);
50 setprop("gear/gear[0]/position-norm",0);
51 setprop("sim/alarms/gear-up-test",0);
52 setprop("sim/model/buccaneer/controls/lp_rotating",0);
53 setprop("sim/model/buccaneer/controls/lp_ospeed",0);
54 setprop("sim/model/buccaneer/controls/lp_ospeed_test",0);
55 setprop("sim/model/buccaneer/controls/lp_ospeed[1]",0);
56 setprop("sim/model/buccaneer/controls/lp_ospeed_test[1]",0);
57
58
59 model_variant_Node = props.globals.getNode("sim/model/livery/variant", 1);
60 model_variant_Node.setIntValue(0);
61
62 model_index_Node = props.globals.getNode("sim/model/livery/index", 1);
63 model_index_Node.setIntValue(0);
64
65 formation_variant_Node = props.globals.getNode("sim/formation/variant", 1);
66 formation_variant_Node.setIntValue(0); 
67
68 formation_index_Node = props.globals.getNode("sim/formation/index", 1);
69 formation_index_Node.setIntValue(0);
70
71 tgt_x_offset_Node = props.globals.getNode("ai/models/wingman/position/tgt-x-offset",1);
72 tgt_y_offset_Node = props.globals.getNode("ai/models/wingman/position/tgt-y-offset",1);
73 tgt_z_offset_Node = props.globals.getNode("ai/models/wingman/position/tgt-z-offset",1);
74 tgt_x_offset_1_Node = props.globals.getNode("ai/models/wingman[1]/position/tgt-x-offset",1);
75 tgt_y_offset_1_Node = props.globals.getNode("ai/models/wingman[1]/position/tgt-y-offset",1);
76 tgt_z_offset_1_Node = props.globals.getNode("ai/models/wingman[1]/position/tgt-z-offset",1);
77 tgt_x_offset_2_Node = props.globals.getNode("ai/models/wingman[2]/position/tgt-x-offset",1);
78 tgt_y_offset_2_Node = props.globals.getNode("ai/models/wingman[2]/position/tgt-y-offset",1);
79 tgt_z_offset_2_Node = props.globals.getNode("ai/models/wingman[2]/position/tgt-z-offset",1);
80
81 props.globals.getNode("/sim/model/formation/position/x-offset",1);
82
83 BLC_Node = props.globals.getNode("controls/flight/BLC",1);
84 BLC_Node.setBoolValue(1);
85
86 effectiveness_Node = props.globals.getNode("/controls/flight/flaps-effectiveness",1);
87 effectiveness_Node.setValue(0);
88
89 aileron_droop_Node = props.globals.getNode("controls/flight/aileron-droop",1);
90 aileron_droop_Node.setValue(0);
91
92 wing_blowing_Node = props.globals.getNode("controls/flight/wing-blowing",1);
93 wing_blowing_Node.setValue(0);
94
95 blc_control_valve_Node = props.globals.getNode("controls/pneumatic/BLC",1);
96 blc_control_valve_Node.setValue(0);
97
98 controls.fullBrakeTime = 0;
99
100 pilot_g = nil;
101 pilot_headshake = nil;
102 observer_headshake = nil;
103 smoke_0 = nil;
104 smoke_1 = nil;
105 wing_blow = nil;
106 #tyresmoke_0 = nil;
107 #tyresmoke_1 = nil;
108 #tyresmoke_2 = nil;
109 flow = nil;
110
111
112 var old_n1 = 0;
113 var time = 0;
114 var dt = 0;
115 var last_time = 0.0;
116 var raining = 0;
117 var mach = 0;
118 var gear = 0;
119 var n1 = 0;
120 var n2 = 0;
121
122 var run_tyresmoke0 = 0;
123 var run_tyresmoke1 = 0;
124 var run_tyresmoke2 = 0;
125
126 var tyresmoke_0 = aircraft.tyresmoke.new(0);
127 var tyresmoke_1 = aircraft.tyresmoke.new(1);
128 var tyresmoke_2 = aircraft.tyresmoke.new(2);
129
130 var xDivergence_damp = 0;
131 var yDivergence_damp = 0;
132 var zDivergence_damp = 0;
133
134 var last_xDivergence = 0;
135 var last_yDivergence = 0;
136 var last_zDivergence = 0;
137
138 var old_xDivergence_damp = 0;
139 var old_yDivergence_damp = 0;
140 var old_zDivergence_damp = 0;
141
142 var lever_sum = 0;
143 var direction = 0 ;
144
145 var formation_dialog = nil;
146
147 var wiper = nil;
148
149 initialize = func {
150
151         print("Initializing Buccaneer utilities ...");
152         
153         # initialise differential braking
154         aircraft.steering.init();
155
156         # initialise dialogs 
157 #aircraft.data.add("sim/model/formation/variant");
158 #       formation_dialog = gui.OverlaySelector.new("Select Formation",
159 #               "Aircraft/Buccaneer/Formations",
160 #               "sim/model/formation/variant", nil, func(no) {
161 #                       formation_variant_Node.setIntValue(no);
162 #                       tgt_x_offset_Node.setDoubleValue(getprop("/sim/model/formation/position/x-offset"));
163 #                       tgt_y_offset_Node.setDoubleValue(getprop("/sim/model/formation/position/y-offset"));
164 #                       tgt_z_offset_Node.setDoubleValue(getprop("/sim/model/formation/position/z-offset"));
165 #                       tgt_x_offset_1_Node.setDoubleValue(getprop("/sim/model/formation/position[1]/x-offset"));
166 #                       tgt_y_offset_1_Node.setDoubleValue(getprop("/sim/model/formation/position[1]/y-offset"));
167 #                       tgt_z_offset_1_Node.setDoubleValue(getprop("/sim/model/formation/position[1]/z-offset"));
168 #                       tgt_x_offset_2_Node.setDoubleValue(getprop("/sim/model/formation/position[2]/x-offset"));
169 #                       tgt_y_offset_2_Node.setDoubleValue(getprop("/sim/model/formation/position[2]/y-offset"));
170 #                       tgt_z_offset_2_Node.setDoubleValue(getprop("/sim/model/formation/position[2]/z-offset"));
171 #               }
172 #       );
173         
174 aircraft.livery.init("Aircraft/Buccaneer/Models/Liveries",
175         "sim/model/livery/variant",
176         "sim/model/livery/index"
177 );
178
179         # initialize objects
180         pilot_g = PilotG.new();
181         pilot_headshake = HeadShake.new("pilot", 0);
182         observer_headshake = HeadShake.new("observer", 100);
183         smoke_0 = Smoke.new(0);
184         smoke_1 = Smoke.new(1);
185         wing_blow = WingBlow.new();
186         tyresmoke_0 = aircraft.tyresmoke.new(0);
187         tyresmoke_1 = aircraft.tyresmoke.new(1);
188         tyresmoke_2 = aircraft.tyresmoke.new(2);
189         flow = Flow.new();
190         var lp = aircraft.lowpass.new(5);
191
192         wiper = aircraft.door.new("sim/model/buccaneer/wiper", 2);
193
194         print ("wiper init ", wiper.getpos());
195         #set listeners
196
197 #       setlistener("engines/engine/cranking", func {smoke.updateSmoking(); 
198 #                                                                                                 });
199
200         setlistener("/sim/signals/fdm-initialized", func {
201         dynamic_view.view_manager.calculate = dynamic_view.view_manager.default_plane; 
202         });
203         
204 #       setlistener("/sim/model/formation/variant", func {
205 #               print("formation listener: ", getprop("/sim/model/formation/position/x-offset"));
206 #               if (tgt_x_offset_Node != nil){
207 #                       print("formation listener getting", getprop("/sim/model/formation/position/x-offset"));
208 #                       tgt_x_offset_Node.setDoubleValue(getprop("/sim/model/formation/position/x-offset"));
209 #                       tgt_y_offset_Node.setDoubleValue(getprop("/sim/model/formation/position/y-offset"));
210 #                       tgt_z_offset_Node.setDoubleValue(getprop("/sim/model/formation/position/z-offset"));
211 #               }
212 #               if (tgt_x_offset_1_Node != nil){
213 #                       tgt_x_offset_1_Node.setDoubleValue(getprop("/sim/model/formation/position[1]/x-offset"));
214 #                       tgt_y_offset_1_Node.setDoubleValue(getprop("/sim/model/formation/position[1]/y-offset"));
215 #                       tgt_z_offset_1_Node.setDoubleValue(getprop("/sim/model/formation/position[1]/z-offset"));
216 #               }
217 #               if (tgt_x_offset_2_Node != nil){
218 #                       tgt_x_offset_2_Node.setDoubleValue(getprop("/sim/model/formation/position[2]/x-offset"));
219 #                       tgt_y_offset_2_Node.setDoubleValue(getprop("/sim/model/formation/position[2]/y-offset"));
220 #                       tgt_z_offset_2_Node.setDoubleValue(getprop("/sim/model/formation/position[2]/z-offset"));
221 #               }
222 #               },
223 #       0,
224 #       1);
225
226         setlistener("sim/model/variant", func {
227                 var index = getprop("sim/model/variant") or 0;
228                 print("set model index", getprop("/sim/model/variant"));
229                 aircraft.livery.set(index);
230         },
231         1);
232
233         setlistener("/sim/model/livery/variant", func {
234                 var name = getprop("sim/model/livery/variant");
235                 forindex (var i; aircraft.livery.data){
236                         print("variant index: ", aircraft.livery.data[i][0]," [1] ",aircraft.livery.data[i][1]);
237                         if(aircraft.livery.data[i][0]== name)
238                                 model_variant_Node.setIntValue(i);
239                 }
240         },
241         1);
242
243         setlistener("controls/flight/aileron-droop", func {
244                 var blc = getprop("controls/flight/BLC");
245                 var droop = getprop("controls/flight/aileron-droop");
246         #       static = 0;
247                 
248                 if ( blc and droop != 0 ){ 
249                         blc_control_valve_Node.setValue(1);
250                 #       effectiveness_Node.setValue(1.8);
251                         wing_blowing_Node.setValue(1);
252                 } else {
253                         blc_control_valve_Node.setValue(0);
254                         wing_blowing_Node.setValue(0);
255                         effectiveness_Node.setValue(1);
256                 }
257                 
258         },
259         1);
260
261         setlistener("controls/flight/BLC", func {
262                 var blc = getprop("controls/flight/BLC");
263         #               static = 0;
264
265                 if ( !blc  ){ 
266                         # effectiveness_Node.setValue(1);
267                         wing_blowing_Node.setValue(0);
268                         blc_control_valve_Node.setValue(0);
269                 } else {
270                         # effectiveness_Node.setValue(2);
271                         wing_blowing_Node.setValue(1.8);
272                         blc_control_valve_Node.setValue(1)
273                 }
274
275         },
276         1);
277
278         setlistener("gear/gear[0]/position-norm", func {
279                 var gear = getprop("gear/gear[0]/position-norm");
280                 
281                 if (gear == 1 ){
282                         run_tyresmoke0 = 1;
283                 }else{
284                         run_tyresmoke0 = 0;
285                 }
286
287                 },
288                 1,
289                 0);
290
291         setlistener("gear/gear[1]/position-norm", func {
292                 var gear = getprop("gear/gear[1]/position-norm");
293                 
294                 if (gear == 1 ){
295                         run_tyresmoke1 = 1;
296                 }else{
297                         run_tyresmoke1 = 0;
298                 }
299
300                 },
301                 1,
302                 0);
303
304         setlistener("gear/gear[2]/position-norm", func {
305                 var gear = getprop("gear/gear[2]/position-norm");
306                 
307                 if (gear == 1 ){
308                         run_tyresmoke2 = 1;
309                 }else{
310                         run_tyresmoke2 = 0;
311                 }
312
313                 },
314                 1,
315                 0);
316
317         setlistener("environment/metar/rain-norm", func (n){
318                 var rain = n.getValue();
319                 var enabled = precipitationcontrolNode.getValue();
320                 print("rain metar", rain, " gui enabled ", enabled);
321                 if(enabled){
322                         rainingNode.setValue(rain);
323                 } else {
324                         rainingNode.setValue(0);
325                         print("rain metar 2", rain, " gui enabled ", enabled, " rain ",rainingNode.getValue());
326                 }
327         },
328         1,
329         0);
330
331         setlistener("sim/rendering/precipitation-gui-enable", func (n){
332                 var enabled = n.getValue();
333                 var rain = getprop("environment/metar/rain-norm");
334                 var internal = view_internal_Node.getValue();
335                 print("rain gui ", rain, " gui enabled ", enabled );
336                 if(enabled and internal){
337                         rainingNode.setValue(rain);
338                         precipitationenabledNode.setBoolValue(0);
339                 } elsif (enabled){
340                         rainingNode.setValue(rain);
341                         precipitationenabledNode.setBoolValue(1);
342                 } else {
343                         rainingNode.setValue(0);
344                         precipitationenabledNode.setBoolValue(0);
345                 }
346
347         },
348         1,
349         0);
350
351         setlistener("sim/current-view/internal", func (n){
352                 var internal = n.getValue();
353                 enabled = precipitationcontrolNode.getValue();
354                 var rain = getprop("environment/metar/rain-norm");
355                 print("precipitation-control-gui-internal",enabled, " internal ", internal, " rain ",rain );
356                 if(internal){
357                         precipitationenabledNode.setBoolValue(0);
358                 } elsif(enabled) {
359                         precipitationenabledNode.setBoolValue(1);
360                         rainingNode.setValue(rain);
361                 }
362
363         },
364         1,
365         0);
366
367 setlistener("/controls/gear/brake-left", func (n){
368                 var brake = n.getValue();
369                 var wow1 = getprop("/gear/gear[1]/wow");
370         var wow2 = getprop("/gear/gear[2]/wow");
371
372         if (!wow1 and !wow2 and brake != 0){
373             setprop("/controls/autoflight/autopilot/ico", 1);
374             print ("/controls/autoflight/autopilot/ico", 1);
375         } else {
376             print ("/controls/autoflight/autopilot/ico", 0);
377         }
378
379         },
380         1,
381         0);
382
383     setlistener("/controls/gear/brake-right", func (n){
384                 var brake = n.getValue();
385                 var wow1 = getprop("/gear/gear[1]/wow");
386         var wow2 = getprop("/gear/gear[2]/wow");
387
388         if (!wow1 and !wow2 and brake != 0){
389             setprop("/controls/autoflight/autopilot/ico", 1);
390             print ("/controls/autoflight/autopilot/ico", 1);
391         } else {
392             print ("/controls/autoflight/autopilot/ico", 0);
393         }
394
395         },
396         1,
397         0);
398
399
400     setlistener("autopilot/locks/altitude", func (n){
401         var lock1 = "altitude-hold-baro";
402         var lock2 = "altitude-hold-radio";
403         var lock3 = "mach-climb";
404         var ico = getprop("/controls/autoflight/autopilot/ico");
405
406         pitchloopid += 1;
407
408         if (n.getValue() == lock1 or n.getValue() == lock2 or n.getValue() == lock3 
409             and ico == 0){
410             print("utils pitch loopid lock", pitchloopid);
411             pitchloop(pitchloopid);
412         } else {
413             print("utils pitch loopid unlock", pitchloopid);
414             pitchloopid = 0;
415         }
416
417     },
418         1,
419         0);
420
421     setlistener("/autopilot/locks/heading", func (n){
422         var lock = "dg-heading-hold";
423         var ico = getprop("/controls/autoflight/autopilot/ico");
424
425         rollloopid += 1;
426
427         if (n.getValue() == lock and ico == 0){
428             print("utils loopid lock", rollloopid);
429             rollloop(rollloopid);
430         } else {
431             print("utils loopid unlock", rollloopid);
432             rollloopid = 0;
433         }
434
435     },
436         1,
437         0);
438
439     setlistener("/controls/autoflight/autopilot/ico", func (n){
440         var lock = getprop("/autopilot/locks/heading");
441         var lock1 = getprop("/autopilot/locks/altitude");
442         rollloopid += 1;
443         pitchloopid += 1;
444
445         if (n.getValue() == 1 ){
446             print("utils ico unlock", rollloopid);
447             rollloopid = 0;
448             pitchloopid = 0;
449         } else {
450
451             if(lock == "dg-heading-hold"){
452                 print("utils ico lock", rollloopid);
453             rollloop(rollloopid);
454             }
455
456             if(lock1 == "altitude-hold-baro" or lock1 == "altitude-hold-radio"
457             or lock1 == "mach-climb"){
458                 pitchloop(pitchloopid);
459             }
460         }
461
462     },
463         1,
464         0);
465
466         # set it running on the next update cycle
467         settimer(update, 0);
468 wiper.open();
469         print("running Buccaneer utilities");
470
471 } # end func
472
473 ###
474 # ====================== end Initialization ========================================
475 ###
476
477 ###
478 # ==== this is the Main Loop which keeps everything updated ========================
479 ##
480 var update = func {
481
482         var time = getprop("sim/time/elapsed-sec");
483         dt = time - last_time;
484         last_time = time;
485
486
487         pilot_g.update();
488         pilot_g.gmeter_update();
489         smoke_0.updateSmoking();
490         smoke_1.updateSmoking();
491         wing_blow.update();
492         var ias = flow.updateFlow(dt);
493
494         if(rainingNode.getValue() and ias < 300){
495                 if(wiper.getpos() == 1 or wiper.getpos() == 0){
496                         wiper.toggle();
497                 }
498         } else {
499                 wiper.close();
500         }
501
502     mach = getprop("velocities/mach");
503     gear = getprop("gear/gear[0]/position-norm");
504     test = getprop("sim/alarms/gear-up-test");
505
506     if ( (mach < 0.25 and gear == 0) or test == 1)
507         setprop("sim/alarms/gear-up", 1);
508     else
509         setprop("sim/alarms/gear-up", 0);
510
511     n1 = getprop("engines/engine[0]/n1");
512     n2 = getprop("engines/engine[0]/n2");
513     n11 = getprop("engines/engine[0]/n1");
514     n21 = getprop("engines/engine[0]/n2");
515
516
517     if (n1 >= 5 or n2 >= 5 or n11 >= 5 or n21 >= 5)
518         setprop("sim/model/buccaneer/controls/lp_rotating",1);
519     else
520         setprop("sim/model/buccaneer/controls/lp_rotating",0);
521
522     test_lp_ospeed  = getprop("sim/model/buccaneer/controls/lp_ospeed_test");
523     test_lp_ospeed1 = getprop("sim/model/buccaneer/controls/lp_ospeed_test[1]");
524
525     if ( n2 > 98 or test_lp_ospeed == 1)
526         setprop("sim/model/buccaneer/controls/lp_ospeed", 1);
527     else
528         setprop("sim/model/buccaneer/controls/lp_ospeed", 0);
529
530     if ( n21 > 98 or test_lp_ospeed1 == 1)
531         setprop("sim/model/buccaneer/controls/lp_ospeed[1]", 1);
532     else
533         setprop("sim/model/buccaneer/controls/lp_ospeed[1]", 0);
534
535
536 #print ("run_tyresmoke ",run_tyresmoke);
537         
538         if (run_tyresmoke0)
539                 tyresmoke_0.update();
540
541         if (run_tyresmoke1)
542                 tyresmoke_1.update();
543
544         if (run_tyresmoke2)
545                 tyresmoke_2.update();
546
547         if (enabledNode.getValue() and view_name_Node.getValue() == "Cockpit View" ) { 
548                 pilot_headshake.update();
549 #               print ("head shake", view_name_Node.getValue());
550         } elsif (enabledNode.getValue() and view_name_Node.getValue() == "Back Seat View") {
551                 observer_headshake.update(); 
552 #       print ( view_name_Node.getValue());
553         }
554
555         settimer(update, 0); 
556
557 }# end main loop func
558
559 # ============================== end Main Loop ===============================
560
561 # ============================== specify classes ===========================
562 # Class that updates wing blowing functions 
563
564 WingBlow = {
565         new : func(name = "wing blowing"){
566                 var obj = {parents : [WingBlow] };
567                 obj.flap_effect = props.globals.getNode("controls/flight/flaps-effectiveness",1);
568                 obj.pressure = 
569                         props.globals.getNode("systems/air-bleed/outputs/main-plane-blowing-stbd",1);
570
571                 obj.name = name;
572                 print (obj.name);
573                 return obj;
574         },
575         update: func (){
576                 var pressure = me.pressure.getValue();
577
578                 if (pressure == nil) return;
579                 var pressure_norm = pressure/75;
580
581 #               Sinusoidal Fit: y=a+b*cos(cx+d)
582 #               Coefficient Data:
583
584                 var a = 1.4866614;
585                 var b = 0.51255151;
586                 var c = 2.5363622;
587                 var d = 3.1629237;
588
589                 var effect = a + b*math.cos(c*pressure_norm + d);
590
591                 if (effect > 2) {
592                         me.flap_effect.setValue(2);
593                 } elsif (effect < 1) { 
594                         me.flap_effect.setValue(1);
595                 } else {
596                         me.flap_effect.setValue(effect);
597                 }
598
599 #               print("update: ", me.flap_effect.getValue());
600         },
601
602 };
603
604
605 # =================================== fuel tank stuff ===================================
606 # Class that specifies fuel cock functions 
607
608 FuelCock = {
609         new : func (name,
610                                 control,
611                                 initial_pos
612                                 ){
613                 var obj = {parents : [FuelCock] };
614                 obj.name = name;
615                 obj.control = props.globals.getNode(control, 1);
616                 obj.control.setIntValue(initial_pos);
617                 
618                 print (obj.name);
619                 return obj;
620         },
621
622         set: func (pos) {# operate fuel cock
623                 me.control.setValue(pos);
624         },
625 }; #
626
627         
628         
629 # ========================== end fuel tank stuff ======================================
630
631
632 # =============================== Pilot G stuff ================================
633 # Class that specifies pilot g functions 
634
635 PilotG = {
636         new : func (name = "pilot-g",
637                                 acceleration = "accelerations",
638                                 pilot_g = "pilot-g",
639                                 g_timeratio = "timeratio", 
640                                 pilot_g_damped = "pilot-g-damped",
641                                 g_min = "pilot-gmin", 
642                                 g_max = "pilot-gmax"
643                                 ){
644                 var obj = {parents : [PilotG] };
645                 obj.name = name;
646                 obj.accelerations = props.globals.getNode("accelerations", 1);
647                 obj.redout = props.globals.getNode("/sim/rendering/redout", 1);
648                 obj.pilot_g = obj.accelerations.getChild(pilot_g, 0, 1);
649                 obj.pilot_g_damped = obj.accelerations.getChild(pilot_g_damped, 0, 1);
650                 obj.g_timeratio = obj.accelerations.getChild(g_timeratio, 0, 1);
651                 obj.g_min = obj.accelerations.getChild(g_min, 0, 1);
652                 obj.g_max = obj.accelerations.getChild(g_max, 0, 1);
653                 obj.pilot_g.setDoubleValue(0);
654                 obj.pilot_g_damped.setDoubleValue(0); 
655                 obj.g_timeratio.setDoubleValue(0.0075);
656                 obj.g_min.setDoubleValue(0);
657                 obj.g_max.setDoubleValue(0);
658 #               print (obj.name," ",obj.g_timeratio.getValue());
659                 return obj;
660         },
661         update : func () {
662                 var n = me.g_timeratio.getValue(); 
663                 var g = me.pilot_g.getValue();
664                 var g_damp = me.pilot_g_damped.getValue();
665
666                 g_damp = (g * n) + (g_damp * (1 - n));
667                 me.pilot_g_damped.setDoubleValue(g_damp);
668
669 #                print(sprintf("pilot_g_damped in=%0.5f, out=%0.5f, alpha=%0.5f",
670 #                         g, g_damp, me.redout_alpha.getValue()));
671         },
672         gmeter_update : func () {
673                 if(me.pilot_g_damped.getValue() < me.g_min.getValue()){
674                         me.g_min.setDoubleValue(me.pilot_g_damped.getValue());
675                 } elsif(me.pilot_g_damped.getValue() > me.g_max.getValue()){
676                         me.g_max.setDoubleValue(me.pilot_g_damped.getValue());
677                 }
678         },
679         get_g_timeratio : func () {
680                 return me.g_timeratio.getValue();
681         },
682 };      
683
684
685
686 # Class that specifies head movement functions under the force of gravity
687
688 #  - this is a modification of the original work by Josh Babcock
689
690         HeadShake = {
691                 new : func (name, index){
692                         var obj = {parents : [HeadShake]};
693                         var x_accel_fps_sec = "x-accel-fps_sec";
694                         var y_accel_fps_sec = "y-accel-fps_sec";
695                         var z_accel_fps_sec = "z-accel-fps_sec";
696 #                       var old_xDivergence_damp = 0;
697 #                       var old_yDivergence_damp = 0;
698 #                       var old_zDivergence_damp = 0;
699                         x_max_m = "x-max-m";
700                         x_min_m = "x-min-m";
701                         y_max_m = "y-max-m";
702                         y_min_m = "y-min-m";
703                         z_max_m = "z-max-m";
704                         z_min_m = "z-min-m";
705                         x_threshold_g = "x-threshold-g";
706                         y_threshold_g = "y-threshold-g";
707                         z_threshold_g = "z-threshold-g";
708                         x_config = "z-offset-m";
709                         y_config = "x-offset-m";
710                         z_config = "y-offset-m";
711                         time_ratio = "time-ratio";
712                         obj.name = name ~ " headshake";
713                         obj.accelerations = props.globals.getNode("accelerations/pilot", 1);
714                         obj.xAccelNode = obj.accelerations.getChild( x_accel_fps_sec, 0, 1);
715                 obj.yAccelNode = obj.accelerations.getChild( y_accel_fps_sec, 0, 1);
716                 obj.zAccelNode = obj.accelerations.getChild( z_accel_fps_sec, 0, 1);
717                 obj.sim = props.globals.getNode("sim/headshake", 1);
718                 obj.xMaxNode = obj.sim.getChild(x_max_m, 0, 1);
719                 obj.xMaxNode.setDoubleValue(0.0375);
720                 obj.xMinNode = obj.sim.getChild(x_min_m, 0, 1);
721                 obj.xMinNode.setDoubleValue(-0.015);
722                 obj.yMaxNode = obj.sim.getChild(y_max_m, 0, 1);
723                 obj.yMaxNode.setDoubleValue(0.015);
724                 obj.yMinNode = obj.sim.getChild(y_min_m, 0, 1);
725                 obj.yMinNode.setDoubleValue(-0.015);
726                 obj.zMaxNode = obj.sim.getChild(z_max_m, 0, 1);
727                 obj.zMaxNode.setDoubleValue(0.015);
728                 obj.zMinNode = obj.sim.getChild(z_min_m, 0, 1);
729                 obj.zMinNode.setDoubleValue(-0.045);
730                 obj.xThresholdNode = obj.sim.getChild(x_threshold_g, 0, 1);
731                 obj.xThresholdNode.setDoubleValue(0.5);
732                 obj.yThresholdNode = obj.sim.getChild(y_threshold_g, 0, 1);
733                 obj.yThresholdNode.setDoubleValue(0.5);
734                 obj.zThresholdNode = obj.sim.getChild(z_threshold_g, 0, 1);
735                 obj.zThresholdNode.setDoubleValue(0.5);
736                 obj.time_ratio_Node = obj.sim.getChild(time_ratio , 0, 1);
737                 obj.time_ratio_Node.setDoubleValue(0.6);
738                 obj.config = props.globals.getNode("sim/view[" ~ index ~"]/config", 1);
739                 obj.xConfigNode = obj.config.getChild(x_config, 0, 1);
740                 obj.yConfigNode = obj.config.getChild(y_config, 0, 1);
741                 obj.zConfigNode = obj.config.getChild(z_config, 0, 1);
742                 obj.seat_vertical_adjust_Node = props.globals.getNode("/controls/seat/vertical-adjust", 1);
743                 obj.seat_vertical_adjust_Node.setDoubleValue(0);
744                 obj.xViewAxisNode = props.globals.getNode("/sim/current-view/z-offset-m");
745                 obj.yViewAxisNode = props.globals.getNode("/sim/current-view/x-offset-m");
746                 obj.zViewAxisNode = props.globals.getNode("/sim/current-view/y-offset-m");
747                 print (obj.name);
748                 return obj;
749         },
750         update : func () {
751
752                 # There are two coordinate systems here, one used for accelerations, 
753                 # and one used for the viewpoint.
754                 # We will be using the one for accelerations.
755
756                 var x_config = "z-offset-m";
757                 var y_config = "x-offset-m";
758                 var z_config = "y-offset-m";
759
760 #               var xConfig = me.xConfigNode.getValue();
761 #       var yConfig = me.yConfigNode.getValue();
762 #               var yConfig = me.xViewAxisNode.getValue();
763 #               var zConfig = me.zConfigNode.getValue();
764                 #print ("yConfig ", yConfig);
765
766                 var n = pilot_g.get_g_timeratio(); 
767                 var seat_vertical_adjust = me.seat_vertical_adjust_Node.getValue();
768
769                 var xMax = me.xMaxNode.getValue();
770                 var xMin = me.xMinNode.getValue();
771                 var yMax = me.yMaxNode.getValue();
772                 var yMin = me.yMinNode.getValue();
773                 var zMax = me.zMaxNode.getValue();
774                 var zMin = me.zMinNode.getValue();
775
776                 #work in G, not fps/s
777                 var xAccel = me.xAccelNode.getValue()/32;
778                 var yAccel = me.yAccelNode.getValue()/32;
779                 var zAccel = (me.zAccelNode.getValue() + 32)/32; # We aren't counting gravity
780  
781                 var xThreshold =  me.xThresholdNode.getValue();
782                 var yThreshold =  me.yThresholdNode.getValue();
783                 var zThreshold =  me.zThresholdNode.getValue();
784                 
785                 # Set viewpoint divergence and clamp
786                 # Note that each dimension has its own special ratio and +X is clamped at 1cm
787                 # to simulate a headrest.
788
789                 if (xAccel < -1) {
790                         xDivergence = (((-0.0506 * xAccel) - (0.538)) * xAccel - (0.9915))
791                                                                                  * xAccel - 0.52;
792                 } elsif (xAccel > 1) {
793                         xDivergence = (((-0.0387 * xAccel) + (0.4157)) * xAccel - (0.8448)) 
794                                                                                         * xAccel + 0.475;
795                 } else {
796                         xDivergence = 0;
797                 }
798
799                 if (yAccel < -0.5) {
800                         yDivergence = (((-0.013 * yAccel) - (0.125)) * yAccel - ( 0.1202)) * yAccel - 0.0272;
801                 } elsif (yAccel > 0.5) {
802                         yDivergence = (((-0.013 * yAccel) + (0.125)) * yAccel - ( 0.1202)) * yAccel + 0.0272;
803                 } else {
804                         yDivergence = 0;
805                 }
806
807                 if (zAccel < -1) {
808                         zDivergence = (((-0.0506 * zAccel) - (0.538)) 
809                                                 * zAccel - (0.9915)) * zAccel - 0.52;
810                 } elsif (zAccel > 1) {
811                         zDivergence = (((-0.0387 * zAccel) + (0.4157)) 
812                                                 * zAccel - (0.8448)) * zAccel + 0.475;
813                 } else {
814                         zDivergence = 0;
815                 }
816                 
817                 xDivergence_total = (xDivergence * 0.25) + (zDivergence * 0.25);
818                 
819                 if (xDivergence_total > xMax){xDivergence_total = xMax; }
820                 if (xDivergence_total < xMin){xDivergence_total = xMin; }
821                 if (abs(last_xDivergence - xDivergence_total) <= xThreshold){
822                         xDivergence_damp = (xDivergence_total * n) + (xDivergence_damp * (1 - n));
823                 #       print ("x low pass");
824                 } else {
825                         xDivergence_damp = xDivergence_total;
826                 #       print ("x high pass");
827                 }
828
829                 last_xDivergence = xDivergence_damp;
830
831 #               print (sprintf("x total=%0.5f, x min=%0.5f, x div damped=%0.5f", xDivergence_total,
832 #                xMin , xDivergence_damp));     
833
834                 yDivergence_total = yDivergence;
835                 if (yDivergence_total >= yMax){yDivergence_total = yMax; }
836                 if (yDivergence_total <= yMin){yDivergence_total = yMin; }
837
838                 if (abs(last_yDivergence - yDivergence_total) <= yThreshold){
839                         yDivergence_damp = (yDivergence_total * n) + (yDivergence_damp * (1 - n));
840 #                       print ("y low pass");
841                 } else {
842                         yDivergence_damp = yDivergence_total;
843 #                       print ("y high pass");
844                 }
845
846                 last_yDivergence = yDivergence_damp;
847
848 #               print (sprintf("y=%0.5f, y total=%0.5f, y min=%0.5f, y div damped=%0.5f",
849 #                                                       yDivergence, yDivergence_total, yMin , yDivergence_damp));
850         
851                 zDivergence_total =  xDivergence + zDivergence;
852                 if (zDivergence_total >= zMax){zDivergence_total = zMax;}
853                 if (zDivergence_total <= zMin){zDivergence_total = zMin;}
854
855                 if (abs(last_zDivergence - zDivergence_total) <= zThreshold){
856                         zDivergence_damp = (zDivergence_total * n) + (zDivergence_damp * (1 - n));
857 #                       print ("z low pass");
858                 } else {
859                         zDivergence_damp = zDivergence_total;
860 #                       print ("z high pass");
861                 }
862         
863                 last_zDivergence = zDivergence_damp;
864         
865 #               print (sprintf("z total=%0.5f, z min=%0.5f, z div damped=%0.5f", 
866 #                                                                                       zDivergence_total, zMin , zDivergence_damp));
867         
868 # Now apply the divergence to the curent viewpoint
869                 
870                 var origin_z = me.xViewAxisNode.getValue() - old_xDivergence_damp;
871                 var origin_x = me.yViewAxisNode.getValue() - old_yDivergence_damp;
872                 var origin_y = me.zViewAxisNode.getValue() - old_zDivergence_damp;
873
874                 me.xViewAxisNode.setDoubleValue(origin_z + xDivergence_damp );
875                 me.yViewAxisNode.setDoubleValue(origin_x + yDivergence_damp );
876                 me.zViewAxisNode.setDoubleValue(origin_y + zDivergence_damp + seat_vertical_adjust );
877
878                 old_xDivergence_damp = xDivergence_damp;
879                 old_yDivergence_damp = yDivergence_damp;
880                 old_zDivergence_damp = zDivergence_damp + seat_vertical_adjust;
881                 },
882         };
883
884
885 # ============================ end Pilot G stuff ============================
886
887 # =========================== smoke stuff ====================================
888 # Class that specifies smoke functions 
889 #
890
891 Smoke = {
892         new : func (number,
893                                 ){
894                 var obj = {parents : [Smoke] };
895                 obj.name = "smoke " ~ number;
896                 obj.n1 = props.globals.getNode("engines/engine[" ~ number ~"]/n1", 1);
897                 obj.smoking = props.globals.getNode("engines/engine[" ~ number ~"]/smoking", 1);
898                 obj.smoking.setBoolValue(0);
899                 obj.old_n1 = 0;
900 #               print (obj.name, " ", number, " ", obj.old_n1);
901                 return obj;
902         },
903
904         updateSmoking: func {    # set the smoke value according to the engine conditions
905 #       print("updating Smoke ", me.name);
906                 
907                 var n1 = me.n1.getValue();
908                 var smoke = me.smoking.getValue();
909                 var diff = 0;
910                 
911                 diff = math.abs(n1 - me.old_n1);
912 #               print("diff ", diff);
913                 
914                 if (n1 <= 65 or diff > 0.1) {
915                         smoke = 1;
916                 } else {
917                         smoke = 0;
918                 }
919         
920                 me.smoking.setBoolValue(smoke);
921                 me.old_n1 = n1;
922                 
923 #               print("smoke ", smoke);
924
925          }, # end function
926
927 }; #
928
929 # =============================== end smoke stuff ================================
930
931 # =========================== tyre smoke stuff ====================================
932 # Class that specifies tyre smoke functions 
933 #
934
935 var TyreSmoke = {
936         new : func (number,
937                                 ){
938                 var obj = {parents : [TyreSmoke] };
939                 obj.name = "tyre-smoke " ~ number;
940                 obj.wow = props.globals.getNode("gear/gear[" ~ number ~"]/wow", 1);
941                 obj.tyresmoke = props.globals.getNode("gear/gear[" ~ number ~"]/tyre-smoke", 1);
942                 obj.tyresmoke.setBoolValue(0);
943                 obj.vertical_speed = props.globals.getNode("velocities/vertical-speed-fps", 1);
944                 obj.speed = props.globals.getNode("velocities/groundspeed-kt", 1);
945                 obj.friction_factor = props.globals.getNode("gear/gear[" ~ number ~"]/ground-friction-factor", 1);
946                 obj.friction_factor.setValue(1);
947                 obj.rollspeed = props.globals.getNode("gear/gear["~ number ~"]/rollspeed-ms", 1);
948                 obj.rollspeed.setValue(0);
949                 obj.lp = aircraft.lowpass.new(2);
950
951 #               print (obj.name, " ", number, " ", obj.tyresmoke.getValue()," ",obj.old_rollspeed);
952                 return obj;
953         },
954
955         update: func {    # set the smoke value according to the conditions
956
957                 var vert_speed = me.vertical_speed.getValue();
958                 var groundspeed = me.speed.getValue();
959                 var friction_factor = me.friction_factor.getValue();
960                 var wow = me.wow.getValue();
961                 var rollspeed = me.rollspeed.getValue();
962                 var filtered_rollspeed = me.lp.filter(me.rollspeed.getValue());
963                 
964                 var diff_norm = 0;
965
966 #       print (me.name, " rollspeed ", rollspeed, " filtered_rollspeed ",filtered_rollspeed);
967
968                 diff = math.abs(rollspeed - filtered_rollspeed);
969
970                 if (diff > 0)
971                         diff_norm = diff/rollspeed;
972                 else
973                         diff_norm = 0;
974
975                 if (wow == nil or diff_norm == nil or rollspeed == nil)
976                         return;
977
978                 if (wow and vert_speed < -0.05 and diff_norm > 0.05 
979                                 and friction_factor > 0.7 and groundspeed > 50){
980                         me.tyresmoke.setValue(1);
981                 }
982                 else{
983                         me.tyresmoke.setValue(0);
984                 }
985
986 #               print("updating ", me.name, " diff ", diff,
987 #                        " diff_norm ", diff_norm, " ", me.tyresmoke.getValue());
988
989          }, # end function
990
991 }; #
992
993 # =============================== end tyre smoke stuff ================================
994 # Class that specifies raindrop flow rate functions
995 #
996
997 Flow = {
998         new : func ()
999         {
1000                 var obj = {parents : [Flow] };
1001                 obj.name = "flow";
1002                 obj.ias = props.globals.getNode("velocities/airspeed-kt", 1);
1003                 obj.elapsed_time = props.globals.getNode("sim/time/elapsed-sec", 1);
1004                 obj.flow = props.globals.getNode("sim/model/buccaneer/flow", 1);
1005                 obj.precipation_level = props.globals.getNode("environment/params/precipitation-level-ft", 1);
1006                 obj.altitude = props.globals.getNode("position/altitude-ft", 1);
1007                 obj.rain = props.globals.getNode("environment/metar/rain-norm", 1);
1008                 obj.flow.setDoubleValue(0);
1009 #               print (obj.name, " ", number, " ", obj.old_n1);
1010                 return obj;
1011         },
1012
1013         updateFlow: func (dt){
1014 #               print("updating: ", me.name," dt ",dt );
1015                 
1016                 var ias = me.ias.getValue();
1017                 var elapsed_time = me.elapsed_time.getValue();
1018                 var altitude = me.altitude.getValue();
1019                 var precipation_level = me.precipation_level.getValue();
1020                 var rain = me.rain.getValue();
1021                 var enabled = precipitationcontrolNode.getValue();
1022
1023                 if (ias < 15){
1024                         me.flow.setDoubleValue(0);
1025                 } else {
1026                         me.flow.setDoubleValue((elapsed_time * 0.5) + (ias * 1852 * dt/(60*60)));
1027                 }
1028                 
1029                 if (altitude > precipation_level or !enabled){
1030                         rainingNode.setValue(0);
1031                 } else {
1032                         rainingNode.setValue(rain);
1033                 }
1034 #               print("updating: ", me.name," dt ",dt, " flow ", me.flow.getValue() );
1035                 return ias;
1036
1037          }, # end function
1038
1039 }; #
1040
1041 # =============================== end rain stuff ================================
1042 # ===== functions which keep the ailerons/elevators zeroised ====================
1043 #
1044
1045 var rollloopid = 0;
1046
1047      var rollloop = func(id) {
1048          id != rollloopid and return;
1049          setprop("/controls/flight/aileron", 0);
1050          settimer(func { rollloop(id) }, 0);
1051      }
1052
1053      var pitchloopid = 0;
1054
1055      var pitchloop = func(id) {
1056          id != pitchloopid and return;
1057          setprop("/controls/flight/elevator", 0);
1058          settimer(func { pitchloop(id) }, 0);
1059      }
1060
1061 # Fire it up
1062
1063 setlistener("sim/signals/fdm-initialized", initialize);
1064
1065 # end