copilot-dual-control.nas 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. ###############################################################################
  2. ## $Id: copilot-dual-control.nas,v 1.5 2010/01/02 09:49:31 vmmeazza Exp $
  3. ##
  4. ## Nasal for copilot for dual control over the multiplayer network.
  5. ##
  6. ## Copyright (C) 2007 - 2009 Anders Gidenstam (anders(at)gidenstam.org)
  7. ## This file is licensed under the GPL license version 2 or later.
  8. ##
  9. ###############################################################################
  10. # Renaming (almost :)
  11. var DCT = dual_control_tools;
  12. var ADC = aircraft_dual_control;
  13. # NOTE: By loading the aircraft specific dual control module
  14. # as <aircraft_dual_control> this file is generic.
  15. # The aircraft specific modul must set the variables
  16. # pilot_type and copilot_type to the name (with full path) of
  17. # main 3d model XML for the pilot and copilot aircraft.
  18. # This module should be loades under the name dual_control.
  19. # Allow aircraft to override the copilot view name. Deprecated.
  20. if (!contains(ADC, "copilot_view")) {
  21. ADC.copilot_view = "Copilot View";
  22. }
  23. # Properties for position and orientation of local aircraft.
  24. var l_lat = "/position/latitude-deg";
  25. var l_lon = "/position/longitude-deg";
  26. var l_alt = "/position/altitude-ft";
  27. var l_heading = "/orientation/heading-deg";
  28. var l_pitch = "/orientation/pitch-deg";
  29. var l_roll = "/orientation/roll-deg";
  30. var l_rudder = "/controls/flight/rudder";
  31. var l_aileron = "/controls/flight/aileron";
  32. var l_elevator = "/controls/flight/elevator";
  33. # Replicate remote state.
  34. var r_airspeed = "velocities/true-airspeed-kt";
  35. var l_airspeed = "/velocities/airspeed-kt";
  36. var vertspeed = "velocities/vertical-speed-fps";
  37. # Default external views to slave to the MP pilot.
  38. var views = {};
  39. views["Helicopter View"] = 2;
  40. views["Chase View"] = 3;
  41. views["Tower View"] = 0;
  42. views["Fly-By View"] = 1;
  43. views["Chase View Without Yaw"] = 1;
  44. ######################################################################
  45. # Connect to new pilot
  46. var process_data = 0;
  47. var connect = func (pilot) {
  48. print("Trying connect pilot to copilot (copilot-dual-control.nas)");
  49. # Set external view eye and target paths.
  50. foreach (var vn; keys(views)) {
  51. var view_cfg = "/sim/view[" ~ view.indexof(vn) ~ "]/config";
  52. setprop(view_cfg ~ "/at-model", 0);
  53. if (views[vn] > 0) {
  54. setprop(view_cfg ~ "/eye-lat-deg-path",
  55. pilot.getNode(DCT.lat_mpp).getPath());
  56. setprop(view_cfg ~ "/eye-lon-deg-path",
  57. pilot.getNode(DCT.lon_mpp).getPath());
  58. setprop(view_cfg ~ "/eye-alt-ft-path",
  59. pilot.getNode(DCT.alt_mpp).getPath());
  60. }
  61. if (views[vn] > 1) {
  62. setprop(view_cfg ~ "/eye-heading-deg-path",
  63. pilot.getNode(DCT.heading_mpp).getPath());
  64. }
  65. if (views[vn] > 2) {
  66. setprop(view_cfg ~ "/eye-pitch-deg-path",
  67. pilot.getNode(DCT.pitch_mpp).getPath());
  68. setprop(view_cfg ~ "/eye-roll-deg-path",
  69. pilot.getNode(DCT.roll_mpp).getPath());
  70. }
  71. setprop(view_cfg ~ "/target-lat-deg-path",
  72. pilot.getNode(DCT.lat_mpp).getPath());
  73. setprop(view_cfg ~ "/target-lon-deg-path",
  74. pilot.getNode(DCT.lon_mpp).getPath());
  75. setprop(view_cfg ~ "/target-alt-ft-path",
  76. pilot.getNode(DCT.alt_mpp).getPath());
  77. setprop(view_cfg ~ "/target-heading-deg-path",
  78. pilot.getNode(DCT.heading_mpp).getPath());
  79. setprop(view_cfg ~ "/target-pitch-deg-path",
  80. pilot.getNode(DCT.pitch_mpp).getPath());
  81. setprop(view_cfg ~ "/target-roll-deg-path",
  82. pilot.getNode(DCT.roll_mpp).getPath());
  83. }
  84. # Tweak MP/AI filters
  85. pilot.getNode("controls/allow-extrapolation").setBoolValue(1);
  86. pilot.getNode("controls/lag-adjust-system-speed").setValue(5.0);
  87. # Set up property aliases
  88. # Set up property mappings.
  89. process_data =
  90. [
  91. # Map /postition/*
  92. DCT.Translator.new
  93. (pilot.getNode(DCT.lat_mpp),
  94. props.globals.getNode(l_lat)),
  95. DCT.Translator.new
  96. (pilot.getNode(DCT.lon_mpp),
  97. props.globals.getNode(l_lon)),
  98. DCT.Translator.new
  99. (pilot.getNode(DCT.alt_mpp),
  100. props.globals.getNode(l_alt)),
  101. # Map /orientation/*
  102. DCT.Translator.new
  103. (pilot.getNode(DCT.heading_mpp),
  104. props.globals.getNode(l_heading)),
  105. DCT.Translator.new
  106. (pilot.getNode(DCT.pitch_mpp),
  107. props.globals.getNode(l_pitch)),
  108. DCT.Translator.new
  109. (pilot.getNode(DCT.roll_mpp),
  110. props.globals.getNode(l_roll)),
  111. # Map /velocities/*
  112. DCT.Translator.new
  113. (pilot.getNode(r_airspeed),
  114. props.globals.getNode(l_airspeed)),
  115. DCT.Translator.new
  116. (pilot.getNode(vertspeed),
  117. props.globals.getNode(vertspeed)),
  118. ] ~ ADC.copilot_connect_pilot(pilot);
  119. print("Dual control ... connected to pilot.");
  120. setprop("/sim/messages/copilot", "Welcome aboard. I'm your pilot !");
  121. }
  122. var disconnect = func {
  123. # Reset external view eye and target paths.
  124. foreach (var vn; keys(views)) {
  125. var view_cfg = "/sim/view[" ~ view.indexof(vn) ~ "]/config";
  126. if (views[vn] > 0) {
  127. setprop(view_cfg ~ "/eye-lat-deg-path",
  128. "/position/latitude-deg");
  129. setprop(view_cfg ~ "/eye-lon-deg-path",
  130. "/position/longitude-deg");
  131. setprop(view_cfg ~ "/eye-alt-ft-path",
  132. "/position/altitude-ft");
  133. }
  134. if (views[vn] > 1) {
  135. setprop(view_cfg ~ "/eye-heading-deg-path",
  136. "/orientation/heading-deg");
  137. }
  138. if (views[vn] > 2) {
  139. setprop(view_cfg ~ "/eye-pitch-deg-path",
  140. "/orientation/pitch-deg");
  141. setprop(view_cfg ~ "/eye-roll-deg-path",
  142. "/orientation/roll-deg");
  143. }
  144. setprop(view_cfg ~ "/target-lat-deg-path",
  145. "/sim/viewer/target/latitude-deg");
  146. setprop(view_cfg ~ "/target-lon-deg-path",
  147. "/sim/viewer/target/longitude-deg");
  148. setprop(view_cfg ~ "/target-alt-ft-path",
  149. "/sim/viewer/target/altitude-ft");
  150. setprop(view_cfg ~ "/target-heading-deg-path",
  151. "/sim/viewer/target/heading-deg");
  152. setprop(view_cfg ~ "/target-pitch-deg-path",
  153. "/sim/viewer/target/pitch-deg");
  154. setprop(view_cfg ~ "/target-roll-deg-path",
  155. "/sim/viewer/target/roll-deg");
  156. }
  157. }
  158. ######################################################################
  159. # Main loop singleton class.
  160. var main = {
  161. init : func {
  162. me.loopid = 0;
  163. me.active = 0;
  164. setlistener("/ai/models/model-added", func {
  165. settimer(func { me.activate(); }, 2);
  166. });
  167. print("Copilot dual control ... initialized");
  168. settimer(func { me.activate(); }, 5);
  169. },
  170. reset : func {
  171. me.active = 0;
  172. me.loopid += 1;
  173. me._loop_(me.loopid);
  174. },
  175. activate : func {
  176. if (!me.active) {
  177. me.reset();
  178. }
  179. },
  180. update : func {
  181. var mpplayers =
  182. props.globals.getNode("/ai/models").getChildren("multiplayer");
  183. var r_callsign = getprop("/sim/remote/pilot-callsign");
  184. foreach (var pilot; mpplayers) {
  185. if ((pilot.getChild("valid").getValue()) and
  186. (pilot.getChild("callsign") != nil) and
  187. (pilot.getChild("callsign").getValue() == r_callsign)) {
  188. if (me.active == 0) {
  189. # Note: sim/model/path contains the model XML file.
  190. if ((pilot.getNode("sim/model/path") != nil) and
  191. (pilot.getNode("sim/model/path").getValue() ==
  192. ADC.pilot_type)) {
  193. me.active = 1;
  194. connect(pilot);
  195. } else {
  196. print("Dual control ... pilot rejected - wrong aircraft type.");
  197. me.loopid += 1;
  198. return;
  199. }
  200. }
  201. # Mess with the MP filters. Highly experimental.
  202. if (pilot.getNode("controls/lag-time-offset") != nil) {
  203. var v = pilot.getNode("controls/lag-time-offset").getValue();
  204. #pilot.getNode("controls/lag-time-offset").setValue(0.99 * v);
  205. }
  206. foreach (var w; process_data) {
  207. w.update();
  208. }
  209. return;
  210. }
  211. }
  212. # The pilot player is not around. Idle loop.
  213. if (me.active) {
  214. print("Dual control ... disconnected from pilot.");
  215. disconnect();
  216. ADC.copilot_disconnect_pilot();
  217. }
  218. me.active = 0;
  219. me.loopid += 1;
  220. },
  221. _loop_ : func(id) {
  222. id == me.loopid or return;
  223. me.update();
  224. settimer(func { me._loop_(id); }, 0);
  225. }
  226. };
  227. ###############################################################################
  228. # Initialization.
  229. var last_view = 0;
  230. setlistener("/sim/signals/fdm-initialized", func {
  231. main.init();
  232. });