The next patch should start to use http://www.flight-manuals-on-cd.com/B314.html
[fg:toms-fgdata.git] / Aircraft / Boeing314 / Nasal / Boeing314-interface.nas
1 # EXPORT : functions ending by export are called from xml
2 # CRON : functions ending by cron are called from timer
3 # SCHEDULE : functions ending by schedule are called from cron
4
5
6
7 # =====
8 # SEATS
9 # =====
10
11 # WARNING : only works if the seats are after the preferences.xml's views.
12
13 Seats = {};
14
15 Seats.new = func {
16    var obj = { parents : [Seats],
17
18                sextant : Sextant.new(),
19
20                controls : nil,
21                positions : nil,
22                theseats : nil,
23                theview : nil,
24
25                lookup : {},
26                names : {},
27                nb_seats : 0,
28
29                CAPTINDEX : 0,
30
31                floating : {},
32                recoverfloating : constant.FALSE,
33                last_recover : {},
34                initial : {}
35          };
36
37    obj.init();
38
39    return obj;
40 };
41
42 Seats.init = func {
43    var name = "";
44    var child = nil;
45
46    me.controls = props.globals.getNode("/controls/seat");
47    me.positions = props.globals.getNode("/systems/seat/position");
48    me.theseats = props.globals.getNode("/systems/seat");
49    me.theviews = props.globals.getNode("/sim").getChildren("view");
50
51    # retrieve the index as created by FG
52    for( var i = 0; i < size(me.theviews); i=i+1 ) {
53         child = me.theviews[i].getChild("name");
54         # nasal doesn't see yet the views of preferences.xml
55         if( child != nil ) {
56             name = me.theviews[i].getChild("name").getValue();
57             if( name == "Engineer View" ) {
58                 me.save_lookup("engineer", i);
59             }
60             elsif( name == "Navigator View" ) {
61                 me.save_lookup("navigator", i);
62                 me.save_initial( "navigator", me.theviews[i] );
63             }
64             elsif( name == "Radio View" ) {
65                 me.save_lookup("radio", i);
66             }
67             elsif( name == "Copilot View" ) {
68                 me.save_lookup("copilot", i);
69             }
70             elsif( name == "Celestial View" ) {
71                 me.save_lookup("celestial", i);
72                 me.save_initial( "celestial", me.theviews[i] );
73             }
74             elsif( name == "Observer View" ) {
75                 me.save_lookup("observer", i);
76                 me.save_initial( "observer", me.theviews[i] );
77             }
78             elsif( name == "Boat View" ) {
79                 me.save_lookup("boat", i);
80             }
81         }
82    }
83
84    # default
85    me.recoverfloating = me.controls.getChild("recover").getValue();
86 }
87
88 Seats.recoverexport = func {
89    me.recoverfloating = !me.recoverfloating;
90    me.controls.getChild("recover").setValue(me.recoverfloating);
91 }
92
93 Seats.viewexport = func( name ) {
94    var index = 0;
95
96    if( name != "captain" ) {
97        index = me.lookup[name];
98
99        # swap to view
100        if( !me.theseats.getChild(name).getValue() ) {
101            setprop("/sim/current-view/view-number", index);
102            me.theseats.getChild(name).setValue(constant.TRUE);
103            me.theseats.getChild("captain").setValue(constant.FALSE);
104
105            me.theviews[index].getChild("enabled").setValue(constant.TRUE);
106        }
107
108        # return to captain view
109        else {
110            setprop("/sim/current-view/view-number", me.CAPTINDEX);
111            me.theseats.getChild(name).setValue(constant.FALSE);
112            me.theseats.getChild("captain").setValue(constant.TRUE);
113
114            me.theviews[index].getChild("enabled").setValue(constant.FALSE);
115        }
116
117        # disable all other views
118        for( var i = 0; i < me.nb_seats; i=i+1 ) {
119             if( name != me.names[i] ) {
120                 me.theseats.getChild(me.names[i]).setValue(constant.FALSE);
121
122                 index = me.lookup[me.names[i]];
123                 me.theviews[index].getChild("enabled").setValue(constant.FALSE);
124             }
125        }
126
127        me.recover();
128    }
129
130    # captain view
131    else {
132        setprop("/sim/current-view/view-number",me.CAPTINDEX);
133        me.theseats.getChild("captain").setValue(constant.TRUE);
134
135        # disable all other views
136        for( var i = 0; i < me.nb_seats; i=i+1 ) {
137             me.theseats.getChild(me.names[i]).setValue(constant.FALSE);
138
139             index = me.lookup[me.names[i]];
140             me.theviews[index].getChild("enabled").setValue(constant.FALSE);
141        }
142    }
143 }
144
145 Seats.scrollexport = func{
146    me.stepView(1);
147 }
148
149 Seats.scrollreverseexport = func{
150    me.stepView(-1);
151 }
152
153 Seats.stepView = func( step ) {
154    var targetview = 0;
155    var name = "";
156
157    for( var i = 0; i < me.nb_seats; i=i+1 ) {
158         name = me.names[i];
159         if( me.theseats.getChild(name).getValue() ) {
160             targetview = me.lookup[name];
161             break;
162         }
163    }
164
165    # ignores captain view
166    if( targetview > me.CAPTINDEX ) {
167        me.theviews[me.CAPTINDEX].getChild("enabled").setValue(constant.FALSE);
168    }
169
170    view.stepView(step);
171
172    # restores because of userarchive
173    if( targetview > me.CAPTINDEX ) {
174        me.theviews[me.CAPTINDEX].getChild("enabled").setValue(constant.TRUE);
175    }
176 }
177
178 # forwards is positiv
179 Seats.movelengthexport = func( name, step ) {
180    var sign = 0;
181    var headdeg = 0.0;
182    var pos = "";
183    var axis = "";
184    var result = constant.FALSE;
185
186    if( me.move() ) {
187        headdeg = getprop("/sim/current-view/goal-heading-offset-deg");
188
189        if( headdeg <= 45 or headdeg >= 315 ) {
190            prop = "/sim/current-view/z-offset-m";
191            sign = 1;
192            axis = "z";
193        }
194        elsif( headdeg >= 135 and headdeg <= 225 ) {
195            prop = "/sim/current-view/z-offset-m";
196            sign = -1;
197            axis = "z";
198        }
199        elsif( headdeg > 225 and headdeg < 315 ) {
200            prop = "/sim/current-view/x-offset-m";
201            sign = -1;
202            axis = "x";
203        }
204        else {
205            prop = "/sim/current-view/x-offset-m";
206            sign = 1;
207            axis = "x";
208        }
209
210        pos = getprop(prop);
211        pos = pos + sign * step;
212        setprop(prop,pos);
213
214        result = constant.TRUE;
215    }
216
217    return result;
218 }
219
220 # left is negativ
221 Seats.movewidthexport = func( name, step ) {
222    var sign = 0;
223    var headdeg = 0.0;
224    var pos = "";
225    var axis = "";
226    var result = constant.FALSE;
227
228    if( me.move() ) {
229        headdeg = getprop("/sim/current-view/goal-heading-offset-deg");
230
231        if( headdeg <= 45 or headdeg >= 315 ) {
232            prop = "/sim/current-view/x-offset-m";
233            sign = 1;
234            axis = "x";
235        }
236        elsif( headdeg >= 135 and headdeg <= 225 ) {
237            prop = "/sim/current-view/x-offset-m";
238            sign = -1;
239            axis = "x";
240        }
241        elsif( headdeg > 225 and headdeg < 315 ) {
242            prop = "/sim/current-view/z-offset-m";
243            sign = 1;
244            axis = "z";
245        }
246        else {
247            prop = "/sim/current-view/z-offset-m";
248            sign = -1;
249            axis = "z";
250        }
251
252        pos = getprop(prop);
253        pos = pos + sign * step;
254        setprop(prop,pos);
255
256        result = constant.TRUE;
257    }
258
259    return result;
260 }
261
262 # up is positiv
263 Seats.moveheightexport = func( name, step ) {
264    var pos = "";
265    var result = constant.FALSE;
266
267    if( me.move() ) {
268        pos = getprop("/sim/current-view/y-offset-m");
269        pos = pos + step;
270        setprop("/sim/current-view/y-offset-m",pos);
271
272        result = constant.TRUE;
273    }
274
275    return result;
276 }
277
278 Seats.save_lookup = func( name, index ) {
279    me.names[me.nb_seats] = name;
280
281    me.lookup[name] = index;
282
283    me.floating[name] = constant.FALSE;
284
285    me.nb_seats = me.nb_seats + 1;
286 }
287
288 # backup initial position
289 Seats.save_initial = func( name, view ) {
290    var pos = {};
291    var config = view.getNode("config");
292
293    pos["x"] = config.getChild("x-offset-m").getValue();
294    pos["y"] = config.getChild("y-offset-m").getValue();
295    pos["z"] = config.getChild("z-offset-m").getValue();
296
297    me.initial[name] = pos;
298
299    me.floating[name] = constant.TRUE;
300    me.last_recover[name] = constant.FALSE;
301 }
302
303 Seats.initial_position = func( name ) {
304    var posx = 0.0;
305    var posy = 0.0;
306    var posz = 0.0;
307    var position = me.positions.getNode(name);
308
309    posx = me.initial[name]["x"];
310    posy = me.initial[name]["y"];
311    posz = me.initial[name]["z"];
312
313    setprop("/sim/current-view/x-offset-m",posx);
314    setprop("/sim/current-view/y-offset-m",posy);
315    setprop("/sim/current-view/z-offset-m",posz);
316
317    position.getChild("x-m").setValue(posx);
318    position.getChild("y-m").setValue(posy);
319    position.getChild("z-m").setValue(posz);
320 }
321
322 Seats.last_position = func( name ) {
323    var posx = 0.0;
324    var posy = 0.0;
325    var posz = 0.0;
326    var position = nil;
327
328    # 1st restore
329    if( !me.last_recover[ name ] and me.recoverfloating ) {
330        position = me.positions.getNode(name);
331
332        posx = position.getChild("x-m").getValue();
333        posy = position.getChild("y-m").getValue();
334        posz = position.getChild("z-m").getValue();
335
336        if( posx != me.initial[name]["x"] or
337            posy != me.initial[name]["y"] or
338            posz != me.initial[name]["z"] ) {
339
340            setprop("/sim/current-view/x-offset-m",posx);
341            setprop("/sim/current-view/y-offset-m",posy);
342            setprop("/sim/current-view/z-offset-m",posz);
343        }
344
345        me.last_recover[ name ] = constant.TRUE;
346    }
347 }
348
349 Seats.recover = func {
350    var name = "";
351
352    for( var i = 0; i < me.nb_seats; i=i+1 ) {
353         name = me.names[i];
354         if( me.theseats.getChild(name).getValue() ) {
355             if( me.floating[name] ) {
356                 me.last_position( name );
357             }
358             break;
359         }
360    }
361 }
362
363 Seats.move_position = func( name ) {
364    var posx = getprop("/sim/current-view/x-offset-m");
365    var posy = getprop("/sim/current-view/y-offset-m");
366    var posz = getprop("/sim/current-view/z-offset-m");
367
368    var position = me.positions.getNode(name);
369
370    position.getChild("x-m").setValue(posx);
371    position.getChild("y-m").setValue(posy);
372    position.getChild("z-m").setValue(posz);
373 }
374
375 Seats.move = func {
376    var name = "";
377    var result = constant.FALSE;
378
379    # saves previous position
380    for( var i = 0; i < me.nb_seats; i=i+1 ) {
381         name = me.names[i];
382         if( me.theseats.getChild(name).getValue() ) {
383             if( me.floating[name] ) {
384                 me.move_position( name );
385                 result = constant.TRUE;
386             }
387             break;
388         }
389    }
390
391    return result;
392 }
393
394 # restore view
395 Seats.restoreexport = func {
396    var name = "";
397
398    for( var i = 0; i < me.nb_seats; i=i+1 ) {
399         name = me.names[i];
400         if( me.theseats.getChild(name).getValue() ) {
401             if( me.floating[name] ) {
402                 me.initial_position( name );
403             }
404             break;
405         }
406    }
407 }
408
409 # restore view pitch
410 Seats.restorepitchexport = func {
411    var index = getprop("/sim/current-view/view-number");
412
413    if( index == me.CAPTINDEX ) {
414        var headingdeg = me.theviews[index].getNode("config").getChild("heading-offset-deg").getValue();
415        var pitchdeg = me.theviews[index].getNode("config").getChild("pitch-offset-deg").getValue();
416
417        setprop("/sim/current-view/heading-offset-deg", headingdeg );
418        setprop("/sim/current-view/pitch-offset-deg", pitchdeg );
419    }
420
421    # only cockpit views
422    else {
423        var name = "";
424
425        for( var i = 0; i < me.nb_seats; i=i+1 ) {
426             name = me.names[i];
427             if( me.theseats.getChild(name).getValue() ) {
428                 var headingdeg = me.theviews[index].getNode("config").getChild("heading-offset-deg").getValue();
429                 var pitchdeg = me.theviews[index].getNode("config").getChild("pitch-offset-deg").getValue();
430
431                 setprop("/sim/current-view/heading-offset-deg", headingdeg );
432                 setprop("/sim/current-view/pitch-offset-deg", pitchdeg );
433                 break;
434             }
435         }
436    }
437 }
438
439 Seats.polarisexport = func {
440     if( !me.theseats.getChild("celestial").getValue() ) {
441         me.viewexport("celestial");
442     }
443
444     me.sextant.polarisexport();
445 }
446
447
448 # ====
449 # MENU
450 # ====
451
452 Menu = {};
453
454 Menu.new = func {
455    var obj = { parents : [Menu],
456
457                autopilot : nil,
458                crew : nil,
459                fuel : nil,
460                gdf : nil,
461                immat : nil,
462                menu : nil,
463                moorage : nil,
464                procedures : {},
465                voice : {}
466          };
467
468    obj.init();
469
470    return obj;
471 };
472
473 Menu.init = func {
474    me.menu = gui.Dialog.new("/sim/gui/dialogs/Boeing314/menu/dialog",
475                             "Aircraft/Boeing314/Dialogs/Boeing314-menu.xml");
476    me.autopilot = gui.Dialog.new("/sim/gui/dialogs/Boeing314/autopilot/dialog",
477                                  "Aircraft/Boeing314/Dialogs/Boeing314-autopilot.xml");
478    me.crew = gui.Dialog.new("/sim/gui/dialogs/Boeing314/crew/dialog",
479                             "Aircraft/Boeing314/Dialogs/Boeing314-crew.xml");
480    me.fuel = gui.Dialog.new("/sim/gui/dialogs/Boeing314/fuel/dialog",
481                             "Aircraft/Boeing314/Dialogs/Boeing314-fuel.xml");
482    me.gdf = gui.Dialog.new("/sim/gui/dialogs/Boeing314/gdf/dialog",
483                             "Aircraft/Boeing314/Dialogs/Boeing314-gdf.xml");
484    me.immat = gui.Dialog.new("/sim/gui/dialogs/Boeing314/immat/dialog",
485                              "Aircraft/Boeing314/Dialogs/Boeing314-immat.xml");
486    me.moorage = gui.Dialog.new("/sim/gui/dialogs/Boeing314/moorage/dialog",
487                                "Aircraft/Boeing314/Dialogs/Boeing314-moorage.xml");
488
489    me.array( me.procedures, 2, "procedures" );
490    me.array( me.voice, 2, "voice" );
491 }
492
493 Menu.immatexport = func {
494    var immatsplit = [ "", "" ];
495    var immat = getprop("/sim/model/immat");
496
497    immatsplit[0] = substr( immat, 0, 2 );
498    immatsplit[1] = substr( immat, 3 );
499
500    setprop("/systems/crew/immat[0]", immatsplit[0]);
501    setprop("/systems/crew/immat[1]", immatsplit[1]);
502 }
503
504 Menu.array = func( table, max, name ) {
505     var j = 0;
506
507     for( var i = 0; i < max; i=i+1 ) {
508        if( j == 0 ) {
509            j = "";
510        }
511        else {
512            j = i + 1;
513        }
514
515        table[i] = gui.Dialog.new("/sim/gui/dialogs/Boeing314/" ~ name ~ "[" ~ i ~ "]/dialog",
516                                  "Aircraft/Boeing314/Dialogs/Boeing314-" ~ name ~ j ~ ".xml");
517     }
518 }
519
520
521 # ========
522 # CREW BOX
523 # ========
524
525 Crewbox = {};
526
527 Crewbox.new = func {
528    var obj = { parents : [Crewbox],
529
530                MENUSEC : 3.0,
531
532                timers : 0.0,
533
534                copilot : nil,
535                copilotcontrol : nil,
536                crew : nil,
537                crewcontrols : nil,
538                engineercontrol : nil,
539                voice : nil,
540
541 # left bottom, 1 line, 10 seconds.
542                BOXX : 10,
543                BOXY : 34,
544                BOTTOMY : -768,
545                LINEY : 20,
546
547                lineindex : { "speedup" : 0, "checklist" : 1, "engineer" : 2, "copilot" : 3 },
548                lasttext : [ "", "", "", "" ],
549                textbox : [ nil, nil, nil, nil ],
550                nblines : 4
551          };
552
553     obj.init();
554
555     return obj;
556 };
557
558 Crewbox.init = func {
559     me.copilot = props.globals.getNode("/systems/copilot");
560     me.copilotcontrol = props.globals.getNode("/controls/copilot");
561     me.crew = props.globals.getNode("/systems/crew");
562     me.crewcontrols = props.globals.getNode("/controls/crew");
563     me.engineer = props.globals.getNode("/systems/engineer");
564     me.engineercontrol = props.globals.getNode("/controls/engineer");
565     me.voice = props.globals.getNode("/systems/voice");
566  
567
568     me.resize();
569
570     setlistener("/sim/startup/ysize", crewboxresizecron);
571     setlistener("/sim/speed-up", crewboxcron);
572     setlistener("/sim/freeze/master", crewboxcron);
573 }
574
575 Crewbox.resize = func {
576     var y = 0;
577     var ysize = - getprop("/sim/startup/ysize");
578
579     if( ysize == nil ) {
580         ysize = me.BOTTOMY;
581     }
582
583     # must clear the text, otherwise text remains after close
584     me.clear();
585
586     for( var i = 0; i < me.nblines; i = i+1 ) {
587          # starts at 700 if height is 768
588          y = ysize + me.BOXY + me.LINEY * i;
589
590          # not really deleted
591          if( me.textbox[i] != nil ) {
592              me.textbox[i].close();
593          }
594
595          # CAUTION : duration is 0 (infinite), or one must wait that the text vanishes device;
596          # otherwise, overwriting the text makes the view popup tip always visible !!!
597          me.textbox[i] = screen.window.new( me.BOXX, y, 1, 0 );
598     }
599
600     me.crewtext();
601     me.pausetext();
602 }
603
604 Crewbox.pausetext = func {
605     var index = me.lineindex["speedup"];
606     var speedup = 0.0;
607     var red = constant.FALSE;
608     var text = "";
609
610     if( getprop("/sim/freeze/master") ) {
611         text = "pause";
612     }
613     else {
614         speedup = getprop("/sim/speed-up");
615         if( speedup > 1 ) {
616             text = sprintf( speedup, "3f.0" ) ~ "  t";
617         }
618         red = constant.TRUE;
619     }
620
621     me.sendpause( index, red, text );
622 }
623
624 crewboxresizecron = func {
625     crewscreen.resize();
626 }
627
628 crewboxcron = func {
629     crewscreen.pausetext();
630 }
631
632 Crewbox.minimizeexport = func {
633     var value = me.crew.getChild("minimized").getValue();
634
635     me.crew.getChild("minimized").setValue(!value);
636
637     me.resettimer();
638 }
639
640 Crewbox.toggleexport = func {
641     # 2D feedback
642     if( !getprop("/systems/human/serviceable") ) {
643         me.crew.getChild("minimized").setValue(constant.FALSE);
644         me.resettimer();
645     }
646
647     # to accelerate display
648     me.crewtext();
649 }
650
651 Crewbox.schedule = func {
652     # timeout on text box
653     if( me.crewcontrols.getChild("timeout").getValue() ) {
654         me.timers = me.timers + me.MENUSEC;
655         if( me.timers >= me.timeoutsec() ) {
656             me.crew.getChild("minimized").setValue(constant.TRUE);
657         }
658     }
659
660     me.crewtext();
661 }
662
663 Crewbox.timeoutsec = func {
664     var result = me.crewcontrols.getChild("timeout-s").getValue();
665
666     if( result < me.MENUSEC ) {
667         result = me.MENUSEC;
668     }
669
670     return result;
671 }
672
673 Crewbox.resettimer = func {
674     me.timers = 0.0;
675
676     me.crewtext();
677 }
678
679 Crewbox.crewtext = func {
680     if( !me.crew.getChild("minimized").getValue() or
681         !me.crewcontrols.getChild("timeout").getValue() ) {
682         me.checklisttext();
683         me.copilottext();
684         me.engineertext();
685     }
686     else {
687         me.clearcrew();
688     }
689 }
690
691 Crewbox.checklisttext = func {
692     var white = constant.FALSE;
693     var text = me.voice.getChild("callout").getValue();
694     var text2 = me.voice.getChild("checklist").getValue();
695     var text = "";
696     var text2 = "";
697     var index = me.lineindex["checklist"];
698
699     if( text2 != "" ) {
700         text = text2 ~ " " ~ text;
701         white = me.voice.getChild("real").getValue();
702     }
703
704     # real checklist is white
705     me.sendtext( index, constant.TRUE, white, text );
706 }
707
708 Crewbox.copilottext = func {
709     var green = constant.FALSE;
710     var text = me.copilot.getChild("state").getValue();
711     var index = me.lineindex["copilot"];
712
713     if( text == "" ) {
714         if( me.copilotcontrol.getChild("activ").getValue() ) {
715             text = "copilot";
716         }
717     }
718
719     if( me.copilot.getChild("activ").getValue() ) {
720         green = constant.TRUE;
721     }
722
723     me.sendtext( index, green, constant.FALSE, text );
724 }
725
726 Crewbox.engineertext = func {
727     var green = me.engineer.getChild("activ").getValue();
728     var text = me.engineer.getChild("state").getValue();
729     var index = me.lineindex["engineer"];
730
731     if( text == "" ) {
732         if( me.engineercontrol.getChild("activ").getValue() ) {
733             text = "engineer";
734         }
735     }
736
737     me.sendtext( index, green, constant.FALSE, text );
738 }
739
740 Crewbox.sendtext = func( index, green, white, text ) {
741     var box = me.textbox[index];
742
743     me.lasttext[index] = text;
744
745     # bright white
746     if( white ) {
747         box.write( text, 1.0, 1.0, 1.0 );
748     }
749
750     # dark green
751     elsif( green ) {
752         box.write( text, 0, 0.7, 0 );
753     }
754
755     # dark yellow
756     else {
757         box.write( text, 0.7, 0.7, 0 );
758     }
759 }
760
761 Crewbox.sendpause = func( index, red, text ) {
762     var box = me.textbox[index];
763
764     me.lasttext[index] = text;
765
766     # bright red
767     if( red ) {
768         box.write( text, 1.0, 0, 0 );
769     }
770     # bright yellow
771     else {
772         box.write( text, 1.0, 1.0, 0 );
773     }
774 }
775
776 Crewbox.clearcrew = func {
777     for( var i = 1; i < me.nblines; i = i+1 ) {
778          if( me.lasttext[i] != "" ) {
779              me.lasttext[i] = "";
780              me.textbox[i].write( me.lasttext[i], 0, 0, 0 );
781          }
782     }
783 }
784
785 Crewbox.clear = func {
786     for( var i = 0; i < me.nblines; i = i+1 ) {
787          if( me.lasttext[i] != "" ) {
788              me.lasttext[i] = "";
789              me.textbox[i].write( me.lasttext[i], 0, 0, 0 );
790          }
791     }
792 }
793
794
795 # =========
796 # VOICE BOX
797 # =========
798
799 Voicebox = {};
800
801 Voicebox.new = func {
802    var obj = { parents : [Voicebox,System],
803
804                seetext : constant.TRUE,
805
806 # centered in the vision field, 1 line, 10 seconds.
807                textbox : screen.window.new( nil, -200, 1, 10 )
808    };
809
810    obj.init();
811
812    return obj;
813 }
814
815 Voicebox.init = func {
816    me.inherit_system("/systems/voice");
817 }
818
819 Voicebox.schedule = func {
820    me.seetext = me.itself["root-ctrl"].getChild("text").getValue();
821 }
822
823 Voicebox.textexport = func {
824    var feedback = "";
825
826    if( me.seetext ) {
827        feedback = "crew text off";
828        me.seetext = constant.FALSE;
829    }
830    else {
831        feedback = "crew text on";
832        me.seetext = constant.TRUE;
833    }
834
835    me.sendtext( feedback, !me.seetext, constant.FALSE, constant.TRUE );
836    me.itself["root-ctrl"].getChild("text").setValue(me.seetext);
837
838    return feedback;
839 }
840
841 Voicebox.is_on = func {
842    return me.seetext;
843 }
844
845 Voicebox.sendtext = func( text, engineer = 0, captain = 0, force = 0 ) {
846    if( me.seetext or force ) {
847        # bright blue
848        if( engineer ) {
849            me.textbox.write( text, 0, 1, 1 );
850        }
851
852        # bright yellow
853        elsif( captain ) {
854            me.textbox.write( text, 1, 1, 0 );
855        }
856
857        # bright green
858        else {
859            me.textbox.write( text, 0, 1, 0 );
860        }
861    }
862 }