rendered paste body###############################################################################
## $Id: copilot-dual-control.nas,v 1.29 2007-11-16 20:29:09 anders Exp $
##
## Nasal for copilot for dual control over the multiplayer network.
##
## Copyright (C) 2007 Anders Gidenstam (anders(at)gidenstam.org)
## This file is licensed under the GPL license.
##
###############################################################################
# Renaming (almost :)
var DCT = dual_control_tools;
var ADC = aircraft_dual_control;
# Properties for position and orientation of local aircraft.
var l_lat = "/position/latitude-deg";
var l_lon = "/position/longitude-deg";
var l_alt = "/position/altitude-ft";
var l_heading = "/orientation/heading-deg";
var l_pitch = "/orientation/pitch-deg";
var l_roll = "/orientation/roll-deg";
# Replicate remote state.
var r_airspeed = "velocities/true-airspeed-kt";
var l_airspeed = "/velocities/airspeed-kt";
var vertspeed = "velocities/vertical-speed-fps";
######################################################################
# Connect to new pilot
var in_data = 0;
var out_data = 0;
var connect = func (pilot) {
# Set view eye paths.
var view_cfg = "/sim/view[" ~ view.indexof("Cockpit View")~ "]/config";
setprop(view_cfg ~ "/eye-lat-deg-path",
pilot.getNode(DCT.lat_mpp).getPath());
setprop(view_cfg ~ "/eye-lon-deg-path",
pilot.getNode(DCT.lon_mpp).getPath());
setprop(view_cfg ~ "/eye-alt-ft-path",
pilot.getNode(DCT.alt_mpp).getPath());
setprop(view_cfg ~ "/eye-heading-deg-path",
pilot.getNode(DCT.heading_mpp).getPath());
setprop(view_cfg ~ "/eye-pitch-deg-path",
pilot.getNode(DCT.pitch_mpp).getPath());
setprop(view_cfg ~ "/eye-roll-deg-path",
pilot.getNode(DCT.roll_mpp).getPath());
view_cfg = "/sim/view[" ~ view.indexof("Helicopter View")~ "]/config";
setprop(view_cfg ~ "/eye-lat-deg-path",
pilot.getNode(DCT.lat_mpp).getPath());
setprop(view_cfg ~ "/eye-lon-deg-path",
pilot.getNode(DCT.lon_mpp).getPath());
setprop(view_cfg ~ "/eye-alt-ft-path",
pilot.getNode(DCT.alt_mpp).getPath());
setprop(view_cfg ~ "/eye-heading-deg-path",
pilot.getNode(DCT.heading_mpp).getPath());
setprop(view_cfg ~ "/at_model", 0);
# Tweak MP/AI filters
pilot.getNode("controls/allow-extrapolation").setBoolValue(1);
pilot.getNode("controls/lag-adjust-system-speed").setValue(5.0);
# Set up property mappings.
in_data =
[
# Map /postition/*
DCT.Translator.new
(pilot.getNode(DCT.lat_mpp), props.globals.getNode(l_lat)),
DCT.Translator.new
(pilot.getNode(DCT.lon_mpp), props.globals.getNode(l_lon)),
DCT.Translator.new
(pilot.getNode(DCT.alt_mpp), props.globals.getNode(l_alt)),
# Map /orientation/*
DCT.Translator.new
(pilot.getNode(DCT.heading_mpp),
props.globals.getNode(l_heading)),
DCT.Translator.new
(pilot.getNode(DCT.pitch_mpp),
props.globals.getNode(l_pitch)),
DCT.Translator.new
(pilot.getNode(DCT.roll_mpp),
props.globals.getNode(l_roll)),
# Map /velocities/*
DCT.Translator.new
(pilot.getNode(r_airspeed),
props.globals.getNode(l_airspeed)),
DCT.Translator.new
(pilot.getNode(vertspeed),
props.globals.getNode(vertspeed)),
] ~ ADC.copilot_in_data(pilot);
out_data = ADC.copilot_out_data(pilot);
print("Dual control ... connected to pilot.");
setprop("/sim/messages/copilot", "Welcome onboard.");
}
######################################################################
# Main loop singleton class.
var main_loop = {
init : func {
me.loopid = 0;
me.active = 0;
setlistener("/ai/models/model-added", me.activate);
print("Copilot dual control ... initialized");
settimer(me.activate, 5);
},
reset : func {
me.loopid += 1;
me._loop_(me.loopid);
},
activate : func {
if (!me.active) {
me.reset();
}
},
update : func {
var mpplayers =
props.globals.getNode("/ai/models").getChildren("multiplayer");
var r_callsign = getprop("/sim/remote/pilot-callsign");
foreach (pilot; mpplayers) {
if ((pilot.getChild("valid").getValue()) and
(pilot.getChild("callsign") != nil) and
(pilot.getChild("callsign").getValue() == r_callsign)) {
if (me.active == 0) {
me.active = 1;
connect(pilot);
}
# Mess with the MP filters. Highly experimental.
if (pilot.getNode("controls/lag-time-offset") != nil) {
var v = pilot.getNode("controls/lag-time-offset").getValue();
#pilot.getNode("controls/lag-time-offset").setValue(0.99 * v);
}
foreach (w; in_data) {
w.update();
}
foreach (w; out_data) {
w.update();
}
return;
}
}
# The pilot player is not around. Idle loop.
me.active = 0;
me.loopid += 1;
print("Dual control ... disconnected from pilot.");
},
_loop_ : func(id) {
id == me.loopid or return;
me.update();
settimer(func { me._loop_(id); }, 0);
}
};
###############################################################################
# Control wrapper overrides.
# Flap control input is -1 for step decrease; 1 for step increase; 0 idle
controls.flapsDown = func {
var val = arg[0];
if(val > 1) { val = 1 } elsif(val < -1) { val = -1 }
setprop(DCT.copilot_flap_mpp, val);
}
# Brake control
controls.applyBrakes = func(v, which = 0) {
if (which <= 0) { setprop(DCT.copilot_lbrake_mpp, v); }
if (which >= 0) { setprop(DCT.copilot_rbrake_mpp, v); }
}
# FIXME: Odd.
controls.applyParkingBrake = func(v) {
if (!v) { return; }
setprop(DCT.copilot_lbrake_mpp, -v);
return 0;
}
###############################################################################
# Initialization.
var last_view = 0;
setlistener("/sim/signals/fdm-initialized", func {
# setlistener("/sim/current-view/view-number", func {
# var vn = getprop("/sim/current-view/view-number");
# if (vn == 0) {
# print("View change to view 0");
# if (last_view != 1) {
# last_view = vn;
# setprop("/sim/current-view/view-number", view.indexof("Chase View"));
# print("View skip");
# } else {
# last_view = vn;
# setprop("/sim/current-view/view-number", view.indexof("Copilot View"));
# }
# }
# });
main_loop.init();
});