yasim-engines.nas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. # Victor Engines - modified by Algernon from generic-yasim-engine.nas
  2. # -- a generic Nasal-based engine control system for YASim
  3. # Version 1.0.0
  4. #
  5. # Copyright (C) 2011 Ryan Miller
  6. #
  7. # This program is free software; you can redistribute it and/or
  8. # modify it under the terms of the GNU General Public License as
  9. # published by the Free Software Foundation; either version 2 of the
  10. # License, or (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful, but
  13. # WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. # General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program; if not, write to the Free Software
  19. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20. #
  21. var UPDATE_PERIOD = 0; # update interval for engine init() functions
  22. print("Loading YASim Engine Script...");
  23. # jet engine class
  24. var Jet =
  25. {
  26. # creates a new engine object
  27. new: func(n, running = 0, idle_throttle = 0.01, max_start_n1 = 5.21, start_threshold = 3, spool_time = 4, start_time = 0.02, shutdown_time = 4,)
  28. {
  29. # copy the Jet object
  30. var m = { parents: [Jet] };
  31. # declare object variables
  32. m.number = n;
  33. m.name = "Engine " ~ ( n + 1 );
  34. m.autostart_status = 0;
  35. m.autostart_id = -1;
  36. m.loop_running = 0;
  37. m.started = 0;
  38. m.starting = 0;
  39. m.idle_throttle = idle_throttle;
  40. m.max_start_n1 = max_start_n1;
  41. m.start_threshold = start_threshold;
  42. m.spool_time = spool_time;
  43. m.start_time = start_time;
  44. m.shutdown_time = shutdown_time;
  45. m.overspeed_rpm = 125; # 111
  46. m.failure_prob = 0.001;
  47. # create references to properties and set default values
  48. m.cutoff = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/cutoff", 1);
  49. m.cutoff.setBoolValue(!running);
  50. m.HPcock = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/HP-cock", 1);
  51. m.HPcock.setBoolValue(0);
  52. m.LPcock = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/LP-cock", 1);
  53. m.LPcock.setBoolValue(0);
  54. m.fuelboost = props.globals.getNode("controls/switches/boost-pump[" ~ n ~ "]", 1);
  55. m.fuelboost.setValue(0);
  56. m.n1 = props.globals.getNode("engines/engine[" ~ n ~ "]/n1", 1);
  57. m.n1.setDoubleValue(0);
  58. m.out_of_fuel = props.globals.getNode("engines/engine[" ~ n ~ "]/out-of-fuel", 1);
  59. m.out_of_fuel.setBoolValue(0);
  60. m.reverser = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/reverser", 1);
  61. m.reverser.setBoolValue(0);
  62. m.rpm = props.globals.getNode("engines/engine[" ~ n ~ "]/rpm", 1);
  63. m.rpm.setDoubleValue(running ? 100 : 0);
  64. m.running = props.globals.getNode("engines/engine[" ~ n ~ "]/running", 1);
  65. m.running.setBoolValue(running);
  66. m.serviceable = props.globals.getNode("engines/engine[" ~ n ~ "]/serviceable", 1);
  67. m.serviceable.setBoolValue(1);
  68. m.starter = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/starter", 1);
  69. m.starter.setBoolValue(0);
  70. m.state = props.globals.getNode("engines/engine[" ~ n ~ "]/state",1 );
  71. m.state.setIntValue(0);
  72. m.sip = props.globals.getNode("engines/engine[" ~ n ~ "]/start-in-progress", 1);
  73. m.sip.setBoolValue();
  74. m.throttle = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/throttle", 1);
  75. m.throttle.setDoubleValue(0);
  76. m.throttle_lever = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/throttle-lever", 1);
  77. m.throttle_lever.setDoubleValue(0);
  78. m.overspeed = props.globals.getNode("engines/engine[" ~ n ~ "]/overspeed",1);
  79. m.overspeed.setBoolValue(0);
  80. m.dambase = props.globals.getNode("sim/damage/damage-zones/engine[" ~ n ~"]",1);
  81. m.damage = m.dambase.getNode("damage-norm", 1);
  82. m.damage.setValue(0);
  83. m.powerloss = m.dambase.getNode("power-loss-norm", 1);
  84. m.powerloss.setValue(0);
  85. m.smoking = m.dambase.getNode("smoke-norm", 1);
  86. m.smoking.setValue(0);
  87. m.fire = m.dambase.getNode("fire", 1);
  88. m.fire.setValue(0);
  89. m.stable = m.dambase.getNode("stable", 1);
  90. m.stable.setBoolValue(1);
  91. m.explosion = m.dambase.getNode("explosion", 1);
  92. m.explosion.setValue(0);
  93. m.mpexplosion = m.dambase.getNode("mp-explosion", 1);
  94. m.mpexplosion.setBoolValue(0);
  95. # return our new object
  96. return m;
  97. },
  98. # engine-specific autostart
  99. autostart: func
  100. {
  101. if (me.autostart_status)
  102. {
  103. me.autostart_status = 0;
  104. me.cutoff.setBoolValue(1);
  105. }
  106. else
  107. {
  108. me.autostart_status = 1;
  109. me.starter.setBoolValue(1);
  110. settimer(func
  111. {
  112. me.cutoff.setBoolValue(0);
  113. }, me.max_start_n1 / me.start_time);
  114. }
  115. },
  116. # creates an engine update loop (optional)
  117. init: func
  118. {
  119. props.globals.getNode("engines/engine["~me.number~"]/serviceable",1).alias("/sim/failure-manager/engines/engine["~me.number~"]/serviceable");
  120. setlistener("/sim/damage/damage-zones/engine["~me.number~"]/damage-norm", func { me.fail_check(); } );
  121. if (me.loop_running) return;
  122. me.loop_running = 1;
  123. var loop = func
  124. {
  125. me.update();
  126. settimer(loop, UPDATE_PERIOD);
  127. };
  128. var fail_loop = func {
  129. me.fail_check();
  130. # Debug
  131. # print("Failure Probability: "~ me.failure_prob);
  132. settimer(fail_loop, 10);
  133. }
  134. settimer(loop, 0);
  135. settimer(fail_loop, 0);
  136. },
  137. # updates the engine
  138. update: func {
  139. me.smoking.setValue( ( me.damage.getValue() * 0.55 ) * ( me.rpm.getValue() * 0.009 ) + ( me.explosion.getValue() * 2 ) + ( me.fire.getValue() * 0.6 ) );
  140. if (me.running.getBoolValue() and !me.started)
  141. {
  142. me.running.setBoolValue(0);
  143. #me.state.setIntValue(0);
  144. }
  145. if ( !me.running.getBoolValue() and me.starter.getBoolValue() ) {
  146. if ( ( me.rpm.getValue() > 0.4 ) and ( me.rpm.getValue() <50 ) ) {
  147. me.sip.setBoolValue(1);
  148. me.state.setIntValue(1);
  149. }
  150. else {
  151. me.sip.setBoolValue(0);
  152. me.state.setIntValue(0);
  153. }
  154. }
  155. else {
  156. me.sip.setBoolValue(0);
  157. }
  158. if (me.cutoff.getBoolValue() or !me.serviceable.getBoolValue() or me.out_of_fuel.getBoolValue())
  159. {
  160. var rpm = me.rpm.getValue();
  161. var time_delta = getprop("sim/time/delta-realtime-sec");
  162. if (me.starter.getBoolValue())
  163. {
  164. rpm += time_delta * me.spool_time;
  165. me.rpm.setValue(rpm >= me.max_start_n1 ? me.max_start_n1 : rpm);
  166. me.state.setIntValue(1);
  167. }
  168. else
  169. {
  170. rpm -= time_delta * me.shutdown_time;
  171. me.rpm.setValue(rpm <= 0 ? 0 : rpm);
  172. me.running.setBoolValue(0);
  173. me.throttle_lever.setDoubleValue(0);
  174. me.started = 0;
  175. if ( rpm > 0.5 ) {
  176. me.state.setIntValue(3);
  177. }
  178. else {
  179. me.state.setIntValue(0);
  180. }
  181. }
  182. }
  183. elsif (me.starter.getBoolValue())
  184. {
  185. var rpm = me.rpm.getValue();
  186. if ( ( rpm >= 20 ) or ( ( rpm >= me.start_threshold ) ) )
  187. {
  188. var time_delta = getprop("sim/time/delta-realtime-sec");
  189. rpm += time_delta * me.spool_time;
  190. me.rpm.setValue(rpm);
  191. if (rpm >= me.n1.getValue())
  192. {
  193. me.running.setBoolValue(1);
  194. me.starter.setBoolValue(0);
  195. me.started = 1;
  196. }
  197. else
  198. {
  199. me.running.setBoolValue(0);
  200. }
  201. }
  202. }
  203. elsif (me.running.getBoolValue())
  204. {
  205. me.throttle_lever.setValue(me.idle_throttle + (1 - me.idle_throttle) * me.throttle.getValue() - me.powerloss.getValue() );
  206. me.rpm.setValue( me.n1.getValue() );
  207. me.state.setIntValue(2);
  208. # me.smoking.setValue( ( me.damage.getValue() * 0.2 ) + ( me.rpm.getValue() * 0.009 ) );
  209. if ( me.rpm.getValue() < me.overspeed_rpm ) { me.overspeed.setBoolValue(0); }
  210. else { me.overspeed.setBoolValue(1); }
  211. }
  212. },
  213. fail_check: func {
  214. var x = rand();
  215. #print("Random Failure Generator: "~x);
  216. if ( me.damage.getValue() > 0.2 ) {
  217. me.stable.setBoolValue(0);
  218. }
  219. if ( me.damage.getValue() > 0.65 ) {
  220. me.serviceable.setBoolValue(0);
  221. }
  222. if (( me.damage.getValue() > 0.85 ) and ( me.running.getBoolValue() )) {
  223. me.explode(0.95);
  224. }
  225. if ( x < me.failure_prob ) {
  226. var sev = 0;
  227. if ( me.failure_prob < 0.01 ) { sev = ( rand() / 5 ); }
  228. else { sev = ( ( rand() + me.damage.getValue() ) / 4 ); }
  229. me.fail(sev);
  230. }
  231. if ( me.overspeed.getBoolValue() ) {
  232. me.failure_prob += (( rand() * 0.01 ) + ( ( ( me.rpm.getValue() * me.failure_prob ) / 1000 ) ));
  233. }
  234. if ( !me.stable.getBoolValue() and me.running.getBoolValue() ) {
  235. # Generate and add random damage
  236. }
  237. },
  238. fail: func (sev = 0.2) {
  239. print("Severity "~sev~" failure on "~ me.name );
  240. #me.damage.setValue( me.damage.getValue() += sev);
  241. var dx = ( me.damage.getValue() + sev );
  242. me.damage.setValue(dx);
  243. me.powerloss.setValue( dx * 4 );
  244. #interpolate(me.powerloss, ( dx * 4 ), 5);
  245. },
  246. explode: func (sev = 0.4) {
  247. print("Explosion in " ~ me.name );
  248. me.explosion.setValue(sev);
  249. interpolate( me.explosion, 0, ( sev * 1.15 ) );
  250. me.mpexplosion.setBoolValue(1);
  251. settimer( func {
  252. me.mpexplosion.setBoolValue(0);
  253. },2);
  254. if ( rand() < 0.85 ) { me.fire.setValue( ( sev + rand() ) * 0.5 ); }
  255. me.fail( sev );
  256. },
  257. };
  258. # Now do it!
  259. # var engine1 = Jet.new(0 , 0 , 0.01 , 5.21 , 4 , 4 , 0.05 , 1);
  260. #var engine2 = Jet.new(1 , 0 , 0.01 , 5.21 , 4 , 4 , 0.05 , 1);
  261. # engine1.init();
  262. # engine2.init();
  263. props.globals.initNode("/sim/autostart/started", 0, "BOOL");
  264. var eng1fuelon = func { setprop("/controls/engines/engine[0]/cutoff", 0); }
  265. var eng1fueloff = func { setprop("/controls/engines/engine[0]/cutoff", 1); }
  266. var eng2fuelon = func { setprop("/controls/engines/engine[1]/cutoff", 0); }
  267. var eng2fueloff = func { setprop("/controls/engines/engine[1]/cutoff", 1); }
  268. var eng1starter = func { setprop("/controls/engines/engine[0]/starter", 1); }
  269. var eng2starter = func { setprop("/controls/engines/engine[1]/starter", 1); }
  270. var eng1start = func {
  271. eng1fueloff();
  272. eng1starter();
  273. settimer(eng1fuelon, 12);
  274. }
  275. var eng2start = func {
  276. eng2fueloff();
  277. eng2starter();
  278. settimer(eng2fuelon, 12);
  279. };
  280. var engstart = func {
  281. settimer(eng1start, 2);
  282. settimer(eng2start, 8);
  283. }
  284. var engstop = func {
  285. eng1fueloff();
  286. eng2fueloff();
  287. }
  288. var autostart = func {
  289. var startstatus = getprop("/sim/autostart/started");
  290. if ( startstatus == 0 ) {
  291. gui.popupTip("Autostarting...");
  292. setprop("/sim/autostart/started", 1);
  293. setprop("/controls/electric/battery-switch", 1);
  294. settimer(engstart, 0.5);
  295. gui.popupTip("Starting Engines");
  296. }
  297. if ( startstatus == 1 ) {
  298. gui.popupTip("Shutting Down...");
  299. setprop("/sim/autostart/started", 0);
  300. eng1fueloff();
  301. eng2fueloff();
  302. }
  303. }
  304. var autostop = func {
  305. eng1fueloff();
  306. eng2fueloff();
  307. apufueloff();
  308. }
  309. print(" ...done.");