1== README.tutorials ===========================================================
2
3FlightGear offers a flexible tutorial system, entirely written in the Nasal
4language. Tutorials can be started and stopped from the "Help" menu. They are
5defined in XML files. Each of them has to be loaded into /sim/tutorials/ under
6a separate tutorial[n]/ branch:
7
8  <sim>
9      <tutorials>
10          <tutorial include="Tutorials/take-off.xml"/>
11          <tutorial include="Tutorials/landing.xml"/>
12      </tutorial>
13  </sim>
14
15Alternatively, all tutorials can be defined in one file, with <tutorial> tags
16around each tutorial. This is then included like so:
17
18  <sim>
19      <tutorials include="foo-tutorials.xml"/>
20  </sim>
21
22Finally, tutorials are automatically generated from any valid checklists
23on startup.  See README.checklists for details.
24
25
26== TUTORIAL STRUCTURE =========================================================
27
28
29A tutorial has this structure, where some of the elements are described
30in detail below:
31
32
33<tutorial>
34  <name>...</name>            mandatory; short identifier, also shown in the
35                                         tutorial selection dialog
36  <description>...</description> mandatory; longer description for the dialog
37  <audio-dir>...</audio-dir>  optional; defines where to load sound samples
38  <timeofday>noon</timeofday> optional; defines daytime; any of "dawn",
39                                        "morning", "noon", "afternoon",
40                                        "evening", "dusk", "midnight", "real"
41
42  <step-time>                 optional; period between each step being executed.
43                              Default 5
44  <exit-time>                 optional; period between exit/abort conditions being
45                              checked. Default 1
46
47  <nasal>
48      ...                     optional; initial Nasal code; see below
49  </nasal>
50
51  <models>
52      ...                     optional; scenery objects; see below
53  </models>
54
55  <targets>
56      ...                     optional; targets; see below
57  </targets>
58
59  <presets>
60      ...                     optional; initial simulator state; see below
61  </presets>
62
63
64  <init>                      optional; initial settings; see below
65    <set>
66        ...                     optional; property settings; allowed multiple
67    </set>                      times
68    <view>
69        ...                     optional; view settings
70    </view>
71    <marker>
72        ...                     optional; marker coordinates
73    </marker>
74    <nasal>
75        ...                     optional; Nasal code
76    </nasal>
77  </init>
78
79  <step>                      mandatory; well, not really, but if there's not
80                              at least one <step>, then the whole tutorial
81                              won't do anything; see below for details
82
83    <message>...</message>      optional; message to be displayed/spoken when
84                                <step> is entered; allowed multiple times, in
85                                which case one is chosen at random
86
87    <message-param>             optional; allowed up to 4 times.
88      <property>...</property>  property to substitute into the <message> string
89    </message-param>            using sprintf() formatting.  E.g. %d, %.2f
90
91    <audio>...</audio>          optional; file name of *.wav sample to be played;
92                                          may be used multiple times (random)
93    <set>
94        ...                     optional; allowed several times
95    </set>
96    <view>
97        ...                     optional
98    </view>
99    <marker>
100        ...                     optional
101    </marker>
102    <nasal>
103        ...                     optional; Nasal code that is executed when the
104    </nasal>                              step is entered
105
106    <wait>10</wait>             optional; wait period after initial messages etc.
107
108    <error>                     optional; allowed several times
109        <message>..</message>       optional; text displayed/spoken
110        <audio>...</audio>          optional; name of *.wav sample to be played
111
112        <condition>
113            ...                     optional, but one should be there to make sense
114        </condition>                          see $FG_ROOT/Docs/README.conditions
115
116        <nasal>
117            ...                     optional; Nasal code that is executed when the
118        </nasal>                              error condition was fulfilled
119    </error>
120
121    <exit>                      optional; defines when to leave this <step>
122        <condition>                       see $FG_ROOT/Docs/README.conditions
123            ...
124        </condition>
125
126        <nasal>
127            ...                     optional; Nasal code that is executed when the
128        </nasal>                              exit condition was met
129    </exit>
130  </step>
131
132
133  <end>                           optional; final settings & actions; see below
134      <message>...</message>          optional; multiple times (random)
135      <audio>...</audio>              optional; multiple times (random)
136      <set>
137          ...                         optional
138      </set>
139      <view>
140          ...                         optional
141      </view>
142      <nasal>
143          ...                         optional
144      </nasal>
145  </end>
146</tutorial>
147
148
149
150After the tutorial has finished initialization, it goes through all <steps>.
151For each it outputs the <message> or <audio>, optionally sets a <marker> and/or
152a <view>, then it checks all <error>s and, if an <error><condition> is fulfilled,
153outputs the respective <error><message>. If none of the <error>s occurred, then
154it checks if the <exit><condition> is true, and if so, it jumps to the next
155<step>. Otherwise the current <step> is endlessly repeated. Finally, after all
156<step>s were processed, the <end> group is executed.
157
158
159
160
161
162
163
164
165== ELEMENTS ===================================================================
166
167
168-- <nasal> --------------------------------------------------------------------
169
170Embedded Nasal is supported on the top level, in <init> in each <step>, in a
171<step>'s <error> and <exit>, and in <end>. All Nasal runs in a separate
172namespace __tutorial, so it's possible to define a function in the <init>'s
173Nasal block, and to use this function in other blocks without prefix. The
174namespace is preloaded with some functions:
175
176
177  next([n=1])      ... to switch n <step>s forward
178  previous([n=1])  ... to switch n <step>s backwards
179
180  say(what [, who="copilot [, delay=0]])
181                   ... says 'what' with voice 'copilot' after 'delay' seconds
182
183
184A Nasal group looks like this:
185
186  <nasal>
187      <script>
188          say("Hi, I'm the pilot!", "pilot");
189      </script>
190      <module>__tutorial</module>           optional; preset with __tutorial
191  </nasal>
192
193
194
195
196
197-- <models> -------------------------------------------------------------------
198
199This loads models into the scenery. It can be used to place, for example,
200a helicopter landing pad at an airport where normally none is, so that the
201tutorial can train landing. The layout is the following, with <path> being
202relative to $FG_ROOT:
203
204  <models>
205      <model>
206          <path>Models/Airport/supacat_winch.ac</path>     mandatory
207          <longitude-deg>-122.4950109</longitude-deg>      mandatory
208          <latitude-deg>37.51403798</latitude-deg>         mandatory
209          <elevation-ft>51</elevation-ft>                  mandatory
210          <heading-deg>2.488888979</heading-deg>           optional (default: 0)
211          <pitch-deg>0</pitch-deg>                         optional (default: 0)
212          <roll-deg>0</roll-deg>                           optional (default: 0)
213      </model>
214
215      <model>
216          ...                      another model
217      </model>
218  </models>
219
220The models are only removed before a new tutorial is loaded. Otherwise they
221remain in the scenery for the whole FlightGear session. They aren't permanently
222added.
223
224
225
226
227
228-- <targets> ------------------------------------------------------------------
229
230These are simple pairs of longitude/latitude under an arbitrary name (here
231"hospital" and "helipad"):
232
233  <targets>
234      <hospital>
235          <longitude-deg>-122.4950109</longitude-deg>      mandatory
236          <latitude-deg>37.51403798</latitude-deg>         mandatory
237      </hospital>
238
239      <helipad>
240          ...
241      </helipad>
242  </targets>
243
244
245The tutorial system will for each calculate how the user's aircraft is positioned
246relative to the respective target, and offer the information in this structure:
247
248  <sim>
249      <tutorials>
250          <targets>
251              <hospital>
252                  <direction-deg>12.345</direction-deg>
253                  <heading-deg>33.333</heading-deg>
254                  <distance-m>12404.932</distance-m>
255                  <eta-min>39.2358</eta-min>
256              </hospital>
257
258              <helipad>
259                  ...
260              </helipad>
261          </targets>
262      </tutorials>
263  </sim>
264
265
266Where:
267  <direction-deg> is an angle between the aircraft's velocity vector and the
268                  azimuth to the target. 0 means that the aircraft is moving
269                  right towards the target. 10 means that the target is slightly
270                  to the right, -90 means that it's exactly left, and -180 or
271                  179.9999 that it's right behind.
272
273  <heading-deg>   is the absolute heading that the aircraft would currently
274                  have to fly with in a straight line to reach the target
275
276  <distance-m>    is the distance in meters
277
278  <eta-min>       is the "Estimated Time of Arrival" given the aircraft's
279                  current speed towards the target. Positive times mean that
280                  the aircraft is getting nearer to the target and can arrive
281                  there in this time given the current speed. It will, of course,
282                  only arrive there, if <direction-deg> is zero. A negative
283                  number means that the aircraft moves away, or in other words:
284                  that in this number of minutes it will be away twice as far.
285
286
287
288
289
290-- <presets> ------------------------------------------------------------------
291
292These set the initial simulator state. All properties are optional.
293The last three entries are to define the position relative to the
294airport/runway or the longitude/latitude.
295
296  <presets>
297      <airport-id>KHAF</airport-id>
298      <on-ground>1</on-ground>
299      <runway>12</runway>
300    <!--
301      <altitude-ft>122.333</altitude-ft>
302      <latitude-deg>37.555</latitude-deg>
303      <longitude-deg>1000</longitude-deg>
304    -->
305      <heading-deg>0</heading-deg>
306      <airspeed-kt>0</airspeed-kt>
307      <glideslope-deg>0</glideslope-deg>
308      <offset-azimuth>0</offset-azimuth>
309      <offset-distance>0</offset-distance>
310  </presets>
311
312
313
314
315
316-- <set> ----------------------------------------------------------------------
317
318<set> groups can be used in <init>, <step>, and <end>. They set a <property>
319to a given <value> or to the value that a second <property> points to. They
320can also reset values that were only temporarily changed for the duration
321of the tutorial. This is desirable for properties that are saved to the
322aircraft config file or to ~/.fgfs/autosave.xml.
323
324  <set>
325      <property>/foo/bar</property>        set /foo/bar to 123
326      <value>123</value>
327  </set>
328
329  <set>
330      <property>/foo/bar</property>        set /foo/bar to value of /test
331      <property>/test</property>
332  </set>
333
334
335
336
337
338-- <view> ---------------------------------------------------------------------
339
340These groups can be used in <init>, <step>, and <end>. They smoothly move the
341view to a new view position/direction. All parameters are optional. If, for
342example, only <field-of-view> is set, then the view will only zoom in -- the
343direction and position will remain the same. This feature is meant for cockpit
344tutorials, where the pilot's view is directed to some switch or instrument.
345view-number can be used to switch between different views, i.e. to tower-view,
346copilot view etc. Default view-number is 0 (captain's view).
347
348  <view>
349      <view-number>0</view-number>                 0=captain's view, 1=copilot,...
350      <heading-offset-deg>20</heading-offset-deg>  positive is left
351      <pitch-offset-deg>-4</pitch-offset-deg>      positive is up
352      <roll-offset-deg>0</roll-offset-deg>         positive is roll right
353      <x-offset-m>0.2</x-offset-m>                 positive is move right
354      <y-offset-m>0.2</y-offset-m>                 positive is move up
355      <z-offset-m>0.2</z-offset-m>                 positive is move back
356      <field-of-view>55</field-of-view>            default: 55; smaller zooms in
357  </view>                                                       bigger zooms out
358
359
360
361
362
363-- <marker> -------------------------------------------------------------------
364
365These are supported in <init>, <step>, and <end>. They show a magenta colored
366circle at given position (relative to aircraft origin) in given size. See the
367last section for how to conveniently find the proper coordinates.
368
369  <marker>
370      <x-m>1.3</x-m>                               positive is back
371      <y-m>0.3</y-m>                               positive is to the right
372      <z-m>0.1</z-m>                               positive is up
373      <scale>1.3</scale>                           optional; default: 1
374  </marker>
375
376
377For this to work, the aircraft model needs to include the tutorial marker
378model in its animation xml file:
379
380  <PropertyList>
381      <path>lightning-f1a.ac</path>
382
383      <model>
384          <path>Aircraft/Generic/marker.xml</path>
385      </model>
386
387      ...
388  </PropertyList>
389
390
391
392
393
394-- <message>/<audio> ----------------------------------------------------------
395
396Groups <step> and <end> can have one or more <message> entries, and one or
397more <audio> entries. If more are used of a kind, then the tutorial chooses
398one at random. If <audio> are available, then the contents are interpreted as
399file name of a *.wav sample, which is appended to the <audio-dir> path defined
400at the <tutorial> top level (default: "") and played by the tutorial system.
401Otherwise the <message> is handed over to the voice system, and synthesized
402to speech by the Festival speech synthesizer (if installed). In either
403case the chosen <message> is displayed on top of the screen. Neither <message>
404nor <audio> are mandatory.
405
406Because one and the same <message> string can be displayed *and* be synthesized,
407which can be problematic in some cases, there is a way to specify parts for
408either display *or* voice synthesizer:  "{<display part>|<voice part}".
409Example:
410
411  <message>Press the {No1|number one} button!</message>
412
413Here, "No1" would be displayed on the screen, but "number one" would be
414sent to the speech synthesis system. This can also be used to add
415invisible but audible exclamation marks:   "Press the button{|!}"
416
417
418
419
420
421-- <condition> ----------------------------------------------------------------
422
423These are explained in detail in $FG_ROOT/Docs/README.conditions. Here's just
424one example:
425
426  <condition>
427      <less-than>
428          <property>/foo/bar</property>
429          <value>12</value>
430      </less-than>
431  </condition>
432
433This condition is true when the value of /foo/bar is less than 12, and false
434otherwise.
435
436
437
438
439
440
441
442
443== FINDING MARKER COORDINATES =================================================
444
445If an aircraft tutorial wants to use the marker, then the aircraft animation
446file needs to include the marker model (see above). If this is done, then one
447can use the "marker-adjust" dialog to find the respective <marker> coordinates.
448Just type this into the "Help->Nasal Console" dialog:
449
450  tutorial.dialog()
451
452
453Or temporarily add a key binding to the *-set.xml file:
454
455  <key n="96">
456      <name>Backtick</name>
457      <desc>Open marker adjust dialog</desc>
458      <binding>
459          <command>dialog-show</command>
460          <dialog-name>marker-adjust</dialog-name>
461      </binding>
462  </key>
463
464
465The dialog allows to move a red cross around, which has the blinking marker
466circle in the middle. Note that ctrl- and shift-modifiers modulate the slider
467movements. Ctrl makes positioning coarser, and shift finer. The [Reset]
468button moves the marker back to aircraft origin, the [Center] button centers
469the sliders, and the [Dump] button dumps the marker coordinates to the
470terminal, for example:
471
472  <marker>
473      <x-m>1.1425</x-m>
474      <y-m>0.1994</y-m>
475      <z-m>-0.0844</z-m>
476      <scale>2.0489</scale>
477  </marker>
478
479This just needs to be copied to the tutorial XML file.
480