1
0
Fork 0

- <targets> can have arbitrary names

- <set> pair: allow to set <property> from <value> or second <property>
- support <set> pairs in <end>, too. This can be used to restore values.
- add optional <view> to <init>/<step>/<exit>/<end>. This is meant for
  cockpit tutorials. See the Lightning's startup tutorial for an example.
This commit is contained in:
mfranz 2007-03-22 17:08:05 +00:00
parent 9a0600b150
commit ef9caa1310

View file

@ -32,16 +32,17 @@
# <pitch-deg> # <pitch-deg>
# <roll-deg # <roll-deg
# #
# <targets> # <targets> - optional; define targets with arbitrary names
# <target> - the tutorial will always keep properties # <foo> - for each target "foo" the tutorial will keep properties
# <longitude-deg> /sim/tutorial/targets/target[*]/{direction-deg,distance-m} # <longitude-deg> /sim/tutorial/targets/foo/{direction-deg,distance-m}
# <latitude-deg> up-to-date for each <target> # <latitude-deg> up-to-date
# #
# <init> - Optional: Initialization section consist of one or more # <init> - Optional: Initialization section consist of one or more
# set nodes: # set nodes, and optionall a view node:
# <set> # <set>
# <property> - Property to set # <property> - Property to set
# <value> - value # <value>/<property> - value or property to set from
# <view>
# #
# <step> - Tutorial step - a segment of the tutorial, consisting of # <step> - Tutorial step - a segment of the tutorial, consisting of
# the following: # the following:
@ -51,6 +52,8 @@
# <audio> - Optional: wav filename to play when displaying # <audio> - Optional: wav filename to play when displaying
# instruction # instruction
# <nasal><script> # <nasal><script>
# <marker>
# <view>
# #
# <error> - Error conditions, causing error messages to be displayed. # <error> - Error conditions, causing error messages to be displayed.
# The tutorial doesn't advance while any error conditions are # The tutorial doesn't advance while any error conditions are
@ -63,11 +66,16 @@
# <exit> - Exit criteria causing tutorial to progress to next step. # <exit> - Exit criteria causing tutorial to progress to next step.
# <condition> - exit condition (see $FG_ROOT/Docs/README.condition) # <condition> - exit condition (see $FG_ROOT/Docs/README.condition)
# <nasal><script> # <nasal><script>
# <view>
# #
# <end> # <end>
# <message>> - Optional: Text to display when the tutorial exits the last step. # <message>> - Optional: Text to display when the tutorial exits the last step.
# <audio> - Optional: wav filename to play when the tutorial exits the last step # <audio> - Optional: wav filename to play when the tutorial exits the last step
# <nasal><script> # <nasal><script>
# <set>
# <property>
# <value>/<property>
# <view>
# #
# #
# NOTE: everywhere where <message> and/or <audio> is supported there can be # NOTE: everywhere where <message> and/or <audio> is supported there can be
@ -128,12 +136,17 @@ var startTutorial = func {
num_step_runs = 0; num_step_runs = 0;
num_errors = 0; num_errors = 0;
steps = tutorial.getChildren("step"); steps = tutorial.getChildren("step");
view.point.save();
set_properties(tutorial.getNode("init"));
set_cursor(tutorial);
set_models(tutorial.getNode("models"));
init_nasal(); init_nasal();
set_marker(tutorial);
run_nasal(tutorial); run_nasal(tutorial);
set_models(tutorial.getNode("models"));
var init = tutorial.getNode("init");
set_properties(init);
set_view(init);
run_nasal(init);
var dir = tutorial.getNode("audio-dir"); var dir = tutorial.getNode("audio-dir");
if (dir != nil) { if (dir != nil) {
@ -173,8 +186,13 @@ var startTutorial = func {
var stopTutorial = func { var stopTutorial = func {
loop_id += 1; loop_id += 1;
if (is_running()) {
var end = tutorial.getNode("end");
set_properties(end);
run_nasal(end);
}
set_marker();
is_running(0); is_running(0);
set_cursor();
} }
_setlistener("/sim/crashed", stopTutorial); _setlistener("/sim/crashed", stopTutorial);
@ -205,19 +223,19 @@ var stepTutorial = func(id) {
var end = tutorial.getNode("end"); var end = tutorial.getNode("end");
say_message(end, "Tutorial finished."); say_message(end, "Tutorial finished.");
say_message(nil, "Deviations: " ~ num_errors); say_message(nil, "Deviations: " ~ num_errors);
run_nasal(end); set_view(end) or view.point.restore();
stopTutorial(); stopTutorial();
return; return;
} }
var step = steps[current_step]; var step = steps[current_step];
set_cursor(step); set_marker(step);
set_view(step.getNode("view"));
set_targets(tutorial.getNode("targets")); set_targets(tutorial.getNode("targets"));
if (num_step_runs == 0) { if (num_step_runs == 0) {
# first time we've encountered this step # first time we've encountered this step
say_message(step, "Tutorial step " ~ current_step); say_message(step, "Tutorial step " ~ current_step);
set_view(step);
set_properties(step); set_properties(step);
run_nasal(step); run_nasal(step);
@ -242,6 +260,7 @@ var stepTutorial = func(id) {
return continue_after(STEP_INTERVAL); return continue_after(STEP_INTERVAL);
} }
run_nasal(exit); run_nasal(exit);
set_view(exit);
} }
# success! # success!
@ -252,7 +271,8 @@ var stepTutorial = func(id) {
# scan all <set> blocks and set their <property> to <value> # scan all <set> blocks and set their <property> to <value> or
# the value of a property that <property n="1"> points to
# <set> # <set>
# <property>/foo/bar</property> # <property>/foo/bar</property>
# <value>woof</value> # <value>woof</value>
@ -261,11 +281,19 @@ var stepTutorial = func(id) {
var set_properties = func(node) { var set_properties = func(node) {
node != nil or return; node != nil or return;
foreach (var c; node.getChildren("set")) { foreach (var c; node.getChildren("set")) {
var p = c.getChild("property").getValue(); var dest = c.getChild("property", 0);
var v = c.getChild("value").getValue(); var src = c.getChild("property", 1);
var val = c.getChild("value");
if (p != nil and v != nil) { dest != nil or die("<set> without <property>");
setprop(p, v); if (val != nil) {
setprop(dest.getValue(), val.getValue());
} elsif (src != nil) {
src = getprop(src.getValue());
src != nil or die("<property n=\"1\"> doesn't refer to defined property");
setprop(dest.getValue(), src);
} else {
die("<set> without <value> or <property n=\"1\">");
} }
} }
} }
@ -277,7 +305,7 @@ var set_targets = func(node) {
var dest = props.globals.getNode("/sim/tutorial/targets", 1); var dest = props.globals.getNode("/sim/tutorial/targets", 1);
var aircraft = geo.aircraft_position(); var aircraft = geo.aircraft_position();
var hdg = heading.getValue() + slip.getValue(); var hdg = heading.getValue() + slip.getValue();
foreach (var t; node.getChildren("target")) { foreach (var t; node.getChildren()) {
var lon = t.getNode("longitude-deg"); var lon = t.getNode("longitude-deg");
var lat = t.getNode("latitude-deg"); var lat = t.getNode("latitude-deg");
if (lon == nil or lat == nil) { if (lon == nil or lat == nil) {
@ -290,7 +318,7 @@ var set_targets = func(node) {
angle -= 360; angle -= 360;
} }
var d = dest.getChild("target", t.getIndex(), 1); var d = dest.getChild(t.getName(), t.getIndex(), 1);
d.getNode("distance-m", 1).setDoubleValue(dist); d.getNode("distance-m", 1).setDoubleValue(dist);
d.getNode("direction-deg", 1).setDoubleValue(angle); d.getNode("direction-deg", 1).setDoubleValue(angle);
} }
@ -328,18 +356,16 @@ var remove_models = func {
var set_view = func(node = nil) { var set_view = func(node = nil) {
node != nil or return; node != nil or return;
if (!size(node.getChildren())) { var v = node.getChild("view");
var name = node.getValue(); if (v != nil) {
node = tutorial.getNode("views"); view.point.move(v);
node != nil or die("<view>name</view>, but no <views> group"); return 1;
node = node.getNode(name);
node != nil or die("<view>name</view> refers to non existing <views> group");
} }
props.copy(node, props.globals.getNode("/sim/current-view")); return 0;
} }
var set_cursor = func(node = nil) { var set_marker = func(node = nil) {
node != nil or return; node != nil or return;
var loc = node.getNode("marker"); var loc = node.getNode("marker");
if (loc == nil) { if (loc == nil) {