recovery.nas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. ###############################################################################
  2. ##
  3. ## Sometimes we crashed our Aircrafts :-(
  4. ## Now we can get help from yasim - multiplayer helicopter pilots :-)
  5. ## The great work from Anders Gidenstamm is the root of this script,
  6. ## written by Marc Kraus :: Lake of Constance Hangar
  7. ##
  8. ## Copyright (C) 2012 - 2014 Marc Kraus (info(at)marc-kraus.de)
  9. ##
  10. ###############################################################################
  11. # =============================================================================
  12. # H-21C Piasecki rescue action for your aircraft
  13. # =============================================================================
  14. var debug = 0;
  15. #Global const
  16. var towel_length = 50.0;
  17. var my_altCor = 0;
  18. #States
  19. var in_the_air = 0;
  20. var in_mount_range = 0;
  21. var delta_roll = 0;
  22. var delta_pitch = 0;
  23. #################################################################################
  24. ############################## crash control ###################################
  25. #If menu ticked open dialog
  26. setlistener("/sar_service/helicopter_rescue", func(oje) {
  27. if(debug) print("Emergency call was canceled ...");
  28. if(oje.getBoolValue()){
  29. sar_service.sar_dialog.show();
  30. in_the_air = 0;
  31. }
  32. }, 1, 0);
  33. #If selected SAR heli
  34. setlistener("/sar_service/sar-callsign", func(sar_callsign) {
  35. if(debug) print("SAR Pilot was selected.");
  36. if(sar_callsign.getValue()){
  37. setprop("/sim/multiplay/chat", "");
  38. setprop("/sim/multiplay/chat", ":: MAYDAY :: MAYDAY :: MAYDAY :: BIRD DOWN!!");
  39. settimer( func { setprop("/sim/multiplay/chat", "I'm here, "~sar_callsign.getValue()~", please help me!"); }, 3);
  40. my_altCor = getprop("/position/altitude-agl-ft");
  41. setprop("/sar_service/sar-locked", 1);
  42. in_the_air = 0;
  43. in_mount_range = 0;
  44. var mp = props.globals.getNode("/ai/models").getChildren("multiplayer");
  45. #Find the SAR ship index number and check that it had't crashed
  46. forindex(var v; mp) {
  47. if(mp[v].getNode("callsign").getValue() == sar_callsign.getValue() and
  48. mp[v].getNode("id").getValue() >= 0){ #Check if not crashed
  49. var sar_index = v;
  50. }
  51. }
  52. if(debug) print(sar_index);
  53. rescue_me(sar_index);
  54. }else{
  55. if(in_the_air == 1) {
  56. setprop("/sar_service/sar-callsign", "");
  57. setprop("/sar_service/sar-locked", 0);
  58. setprop("/sim/crashed",0);
  59. }
  60. setprop("/sar_service/helicopter_rescue",0);
  61. setprop("/sar_service/sar-locked",0);
  62. setprop("/controls/shadow-and-fire", 1);
  63. in_mount_range = 0;
  64. }
  65. }, 1, 0);
  66. ############################### Rescue procedure ###############################
  67. var rescue_me = func(v) {
  68. if (v != nil and v >= 0){
  69. var sar_mp = props.globals.getNode("/ai/models/multiplayer[" ~v~ "]");
  70. yourLocked = getprop("/sar_service/sar-locked") or 0;
  71. #If heli selected and message sent
  72. if(yourLocked){
  73. var my_alt = props.globals.getNode("/position/altitude-ft");
  74. var my_alt_m = my_alt.getValue()*FT2M;
  75. var my_pos_lat = getprop("/position/latitude-deg");
  76. var my_pos_lon = getprop("/position/longitude-deg");
  77. var heaving_heli_alt = getprop("/ai/models/multiplayer["~v~"]/position/altitude-ft") - towel_length;
  78. var my_alt_agl = (my_alt_m - geo.elevation( my_pos_lat, my_pos_lon, my_alt_m)) * M2FT;
  79. var ground = my_alt_agl - my_altCor ;
  80. # if we are on ground and not on heaving procedure, look for the distance to the hook
  81. if (in_the_air == 0){
  82. var sar_pos_lat = getprop("/ai/models/multiplayer["~v~"]/position/latitude-deg");
  83. var sar_pos_lon = getprop("/ai/models/multiplayer["~v~"]/position/longitude-deg");
  84. if((math.abs(sar_pos_lat - my_pos_lat) <= 0.00008) and (math.abs(sar_pos_lon - my_pos_lon) <= 0.0012)){
  85. in_mount_range = 1;
  86. }else{
  87. in_mount_range = 0;
  88. }
  89. }
  90. #In range and not touching gnd
  91. if(ground >= -0.0001 and in_mount_range){
  92. in_the_air = 1;
  93. setprop("/controls/shadow-and-fire", 0);
  94. setprop("/sim/crashed", 1);
  95. my_alt.setValue(heaving_heli_alt);
  96. setprop("/position/altitude-agl-ft",my_alt_agl);
  97. setprop("/position/longitude-deg", getprop("/ai/models/multiplayer["~v~"]/position/longitude-deg"));
  98. setprop("/position/latitude-deg", getprop("/ai/models/multiplayer["~v~"]/position/latitude-deg"));
  99. var pitch= getprop("/orientation/pitch-deg") - delta_pitch;
  100. var roll = getprop("/orientation/roll-deg") - delta_roll;
  101. delta_pitch = getprop("/ai/models/multiplayer["~v~"]/orientation/pitch-deg");
  102. delta_roll = getprop("/ai/models/multiplayer["~v~"]/orientation/roll-deg");
  103. setprop("/orientation/pitch-deg", pitch + delta_pitch);
  104. setprop("/orientation/roll-deg", roll + delta_roll);
  105. setprop("/sim/multiplay/generic/float[20]", getprop("/yasim/gross-weight-lbs"));
  106. if(debug){
  107. print("Lifting operation runing.");
  108. print("Ground: "~ground);
  109. print("my_alt: "~my_alt.getValue());
  110. print("heaving__alt "~heaving_heli_alt);
  111. print("mounted "~in_mount_range);
  112. }
  113. }else{ # Not hooked
  114. if(in_the_air == 1) {
  115. setprop("/sar_service/sar-callsign", "");
  116. setprop("/sar_service/sar-locked", 0);
  117. setprop("/sim/crashed",0);
  118. }
  119. in_mount_range = 0;
  120. in_the_air = 0;
  121. }
  122. settimer( func { rescue_me(v); }, 0);
  123. # No heli selected
  124. }else{
  125. # if nobody is in range... nobody can help. So set /sar_service back to 0
  126. # setprop("/sim/crashed",0);
  127. setprop("/sar_service/helicopter_rescue",0);
  128. setprop("/sar_service/sar-callsign","");
  129. setprop("/controls/shadow-and-fire", 1);
  130. in_mount_range = 0;
  131. if(in_the_air == 1) {
  132. setprop("/sim/crashed",0);
  133. }
  134. in_the_air = 0;
  135. if(debug) print("Hook released.");
  136. }
  137. } # end v nil control
  138. }
  139. #Set new menu entry
  140. var list= props.globals.getNode("/sim/menubar/default").getChildren("menu");
  141. var menup = "/sim/menubar/default/menu[" ~ size(list) ~ "]/";
  142. setprop (menup ~ "enabled", 'true');
  143. setprop (menup ~ "label", "SAR");
  144. #Set new SAR item
  145. var m_item = menup ~ "item/";
  146. setprop (m_item ~ "label", "Call SAR helicopter");
  147. setprop (m_item ~ "binding/command", "property-assign");
  148. setprop (m_item ~ "binding/property", "/sar_service/helicopter_rescue");
  149. setprop (m_item ~ "binding/value", 1);
  150. fgcommand("gui-redraw");
  151. ################## new menu for the SAR Pilot selection ########################
  152. var SAR_DLG = 0;
  153. var sar_dialog = {};
  154. ############################################################
  155. sar_dialog.init = func (x = nil, y = nil) {
  156. me.x = x;
  157. me.y = y;
  158. me.bg = [0, 0, 0, 0.3]; # background color
  159. me.fg = [[1.0, 1.0, 1.0, 1.0]];
  160. #
  161. # "private"
  162. me.title = "SAR";
  163. me.basenode = props.globals.getNode("/sar_service", 1);
  164. me.dialog = nil;
  165. me.namenode = props.Node.new({"dialog-name" : me.title });
  166. me.listeners = [];
  167. }
  168. ############################################################
  169. sar_dialog.create = func {
  170. if (me.dialog != nil)
  171. me.close();
  172. me.dialog = gui.Widget.new();
  173. me.dialog.set("name", me.title);
  174. if (me.x != nil)
  175. me.dialog.set("x", me.x);
  176. if (me.y != nil)
  177. me.dialog.set("y", me.y);
  178. me.dialog.set("layout", "vbox");
  179. me.dialog.set("default-padding", 0);
  180. var titlebar = me.dialog.addChild("group");
  181. titlebar.set("layout", "hbox");
  182. titlebar.addChild("empty").set("stretch", 1);
  183. titlebar.addChild("text").set("label", "SAR pilots in range");
  184. var w = titlebar.addChild("button");
  185. w.set("pref-width", 16);
  186. w.set("pref-height", 16);
  187. w.set("legend", "");
  188. w.set("default", 0);
  189. w.set("key", "esc");
  190. w.setBinding("nasal", "sar_service.sar_dialog.destroy(); ");
  191. w.setBinding("dialog-close");
  192. me.dialog.addChild("hrule");
  193. var content = me.dialog.addChild("group");
  194. content.set("layout", "vbox");
  195. content.set("halign", "center");
  196. content.set("default-padding", 5);
  197. # Generate the dialog contents.
  198. me.players = me.find_sar_players();
  199. var i = 0;
  200. var tmpbase = me.basenode.getNode("dialog", 1);
  201. var selected = me.basenode.getNode("sar-callsign").getValue();
  202. foreach (var p; me.players) {
  203. var tmp = tmpbase.getNode("b[" ~ i ~ "]", 1);
  204. tmp.setBoolValue(streq(selected, p));
  205. var w = content.addChild("checkbox");
  206. w.node.setValues({"label" : p,
  207. "halign" : "left",
  208. "property" : tmp.getPath()});
  209. w.setBinding
  210. ("nasal",
  211. "sar_service.sar_dialog.select_action(" ~ i ~ ");");
  212. i = i + 1;
  213. }
  214. me.dialog.addChild("hrule");
  215. # Display the dialog.
  216. fgcommand("dialog-new", me.dialog.prop());
  217. fgcommand("dialog-show", me.namenode);
  218. }
  219. ############################################################
  220. sar_dialog.close = func {
  221. fgcommand("dialog-close", me.namenode);
  222. }
  223. ############################################################
  224. sar_dialog.destroy = func {
  225. SAR_DLG = 0;
  226. me.close();
  227. me.basenode.getNode("helicopter_rescue").setValue(0);
  228. foreach(var l; me.listeners)
  229. removelistener(l);
  230. delete(gui.dialog, "\"" ~ me.title ~ "\"");
  231. }
  232. ############################################################
  233. sar_dialog.show = func {
  234. # print("Showing MPCopilots dialog!");
  235. if (!SAR_DLG) {
  236. SAR_DLG = int(getprop("/sim/time/elapsed-sec"));
  237. me.init();
  238. me.create();
  239. me._update_(SAR_DLG);
  240. }
  241. }
  242. ############################################################
  243. sar_dialog._redraw_ = func {
  244. if (me.dialog != nil) {
  245. me.close();
  246. me.create();
  247. }
  248. }
  249. ############################################################
  250. sar_dialog._update_ = func (id) {
  251. if (SAR_DLG != id) return;
  252. me._redraw_();
  253. settimer(func { me._update_(id); }, 5.0);
  254. }
  255. ############################################################
  256. sar_dialog.select_action = func (n) {
  257. var selected = me.basenode.getNode("sar-callsign").getValue();
  258. var bs = me.basenode.getNode("dialog").getChildren();
  259. # Assumption: There are two true b:s or none. The one not matching selected
  260. # is the new selection.
  261. var i = 0;
  262. me.basenode.getNode("sar-callsign").setValue("");
  263. foreach (var b; bs) {
  264. if (!b.getValue() and (i == n)) {
  265. b.setValue(1);
  266. me.basenode.getNode("sar-callsign").setValue(me.players[i]);
  267. } else {
  268. b.setValue(0);
  269. }
  270. i = i + 1;
  271. }
  272. #dual_control.main.reset();
  273. me._redraw_();
  274. }
  275. ############################################################
  276. # Return a list containing all nearby copilot players of the right type.
  277. sar_dialog.find_sar_players = func {
  278. var mpplayers =
  279. props.globals.getNode("/ai/models").getChildren("multiplayer");
  280. var res = [];
  281. foreach (var pilot; mpplayers) {
  282. if ((pilot.getNode("valid") != nil) and
  283. (pilot.getNode("valid").getValue()) and
  284. (pilot.getNode("sim/model/path") != nil)) {
  285. var type = pilot.getNode("sim/model/path").getValue();
  286. #Old validation code. Change later to "self published SAR" aircraft filter
  287. # foreach (var type_id; me.sar_type){
  288. # if (streq(type,type_id)) {
  289. # append(res, pilot.getNode("callsign").getValue());
  290. # }
  291. # }
  292. append(res, pilot.getNode("callsign").getValue());
  293. }
  294. }
  295. # debug.dump(res);
  296. return res;
  297. }
  298. ###############################################################################