engines.nas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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("Initialising Yasim Engines");
  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 = 121; # 111
  46. m.failure_prob = 0;
  47. m.crashed = props.globals.getNode("/sim/crashed");
  48. # create references to properties and set default values
  49. m.cutoff = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/cutoff", 1);
  50. m.cutoff.setBoolValue(!running);
  51. m.HPcock = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/HP-cock", 1);
  52. m.HPcock.setBoolValue(0);
  53. m.LPcock = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/LP-cock", 1);
  54. m.LPcock.setBoolValue(0);
  55. m.n1 = props.globals.getNode("engines/engine[" ~ n ~ "]/n1", 1);
  56. m.n1.setDoubleValue(0);
  57. m.out_of_fuel = props.globals.getNode("engines/engine[" ~ n ~ "]/out-of-fuel", 1);
  58. m.out_of_fuel.setBoolValue(0);
  59. m.reverser = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/reverser", 1);
  60. m.reverser.setBoolValue(0);
  61. m.rpm = props.globals.getNode("engines/engine[" ~ n ~ "]/rpm", 1);
  62. m.rpm.setDoubleValue(running ? 100 : 0);
  63. m.running = props.globals.getNode("engines/engine[" ~ n ~ "]/running", 1);
  64. m.running.setBoolValue(running);
  65. m.serviceable = props.globals.getNode("engines/engine[" ~ n ~ "]/serviceable", 1);
  66. m.serviceable.setBoolValue(1);
  67. m.starter = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/starter", 1);
  68. m.starter.setBoolValue(0);
  69. m.state = props.globals.getNode("engines/engine[" ~ n ~ "]/state",1 );
  70. m.state.setIntValue(0);
  71. m.sip = props.globals.getNode("engines/engine[" ~ n ~ "]/start-in-progress", 1);
  72. m.sip.setBoolValue();
  73. m.throttle = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/throttle", 1);
  74. m.throttle.setDoubleValue(0);
  75. m.throttle_lever = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/throttle-lever", 1);
  76. m.throttle_lever.setDoubleValue(0);
  77. m.reheat = props.globals.getNode("engines/engine[" ~ n ~ "]/reheat",1 );
  78. m.reheat.setValue(0);
  79. m.overspeed = props.globals.getNode("engines/engine[" ~ n ~ "]/overspeed",1);
  80. m.overspeed.setBoolValue(0);
  81. m.dambase = props.globals.getNode("sim/damage/damage-zones/engine[" ~ n ~"]",1);
  82. m.damage = m.dambase.getNode("damage-norm", 1);
  83. m.damage.setValue(0);
  84. m.powerloss = m.dambase.getNode("power-loss-norm", 1);
  85. m.powerloss.setValue(0);
  86. m.smoking = m.dambase.getNode("smoke-norm", 1);
  87. m.smoking.setValue(0);
  88. m.fire = m.dambase.getNode("fire", 1);
  89. m.fire.setValue(0);
  90. m.stable = m.dambase.getNode("stable", 1);
  91. m.stable.setBoolValue(1);
  92. m.explosion = m.dambase.getNode("explosion", 1);
  93. m.explosion.setValue(0);
  94. m.mpexplosion = m.dambase.getNode("mp-explosion", 1);
  95. m.mpexplosion.setBoolValue(0);
  96. # return our new object
  97. return m;
  98. },
  99. # engine-specific autostart
  100. autostart: func
  101. {
  102. if (me.autostart_status)
  103. {
  104. me.autostart_status = 0;
  105. me.cutoff.setBoolValue(1);
  106. }
  107. else
  108. {
  109. me.autostart_status = 1;
  110. me.starter.setBoolValue(1);
  111. settimer(func
  112. {
  113. me.cutoff.setBoolValue(0);
  114. }, me.max_start_n1 / me.start_time);
  115. }
  116. },
  117. # creates an engine update loop (optional)
  118. init: func
  119. {
  120. props.globals.getNode("engines/engine["~me.number~"]/serviceable",1).alias("/sim/failure-manager/engines/engine["~me.number~"]/serviceable");
  121. setlistener("/sim/damage/damage-zones/engine["~me.number~"]/damage-norm", func { me.fail_check(); } );
  122. if (me.loop_running) return;
  123. me.loop_running = 1;
  124. var loop = func
  125. {
  126. me.update();
  127. settimer(loop, UPDATE_PERIOD);
  128. };
  129. var fail_loop = func {
  130. me.fail_check();
  131. # Debug
  132. #print("Failure Probability: "~ me.failure_prob);
  133. settimer(fail_loop, 10);
  134. }
  135. settimer(loop, 0);
  136. settimer(fail_loop, 0);
  137. },
  138. # updates the engine
  139. update: func {
  140. me.smoking.setValue( ( me.damage.getValue() * 0.55 ) + ( me.explosion.getValue() * 2 ) + ( me.fire.getValue() * 0.6 ) );
  141. if (me.running.getBoolValue() and !me.started)
  142. {
  143. me.running.setBoolValue(0);
  144. #me.state.setIntValue(0);
  145. }
  146. if ( !me.running.getBoolValue() and me.starter.getBoolValue() ) {
  147. if ( ( me.rpm.getValue() > 0.4 ) and ( me.rpm.getValue() <50 ) ) {
  148. me.sip.setBoolValue(1);
  149. me.state.setIntValue(1);
  150. }
  151. else {
  152. me.sip.setBoolValue(0);
  153. me.state.setIntValue(0);
  154. }
  155. }
  156. else {
  157. me.sip.setBoolValue(0);
  158. }
  159. if (me.cutoff.getBoolValue() or !me.serviceable.getBoolValue() or me.out_of_fuel.getBoolValue() )
  160. {
  161. var rpm = me.rpm.getValue();
  162. var time_delta = getprop("sim/time/delta-realtime-sec");
  163. if (me.starter.getBoolValue())
  164. {
  165. rpm += time_delta * me.spool_time;
  166. me.rpm.setValue(rpm >= me.max_start_n1 ? me.max_start_n1 : rpm);
  167. me.state.setIntValue(1);
  168. }
  169. else
  170. {
  171. rpm -= time_delta * me.shutdown_time;
  172. me.rpm.setValue(rpm <= 0 ? 0 : rpm);
  173. me.running.setBoolValue(0);
  174. me.throttle_lever.setDoubleValue(0);
  175. me.started = 0;
  176. if ( rpm > 0.5 ) {
  177. me.state.setIntValue(3);
  178. }
  179. else {
  180. me.state.setIntValue(0);
  181. }
  182. }
  183. }
  184. elsif (me.starter.getBoolValue())
  185. {
  186. var rpm = me.rpm.getValue();
  187. if (rpm >= me.start_threshold)
  188. {
  189. var time_delta = getprop("sim/time/delta-realtime-sec");
  190. rpm += time_delta * me.spool_time;
  191. me.rpm.setValue(rpm);
  192. if (rpm >= me.n1.getValue())
  193. {
  194. me.running.setBoolValue(1);
  195. me.starter.setBoolValue(0);
  196. me.started = 1;
  197. }
  198. else
  199. {
  200. me.running.setBoolValue(0);
  201. }
  202. }
  203. }
  204. elsif (me.running.getBoolValue())
  205. {
  206. if (!me.crashed.getBoolValue()) {
  207. me.throttle_lever.setValue(me.idle_throttle + (1 - me.idle_throttle) * me.throttle.getValue() - me.powerloss.getValue() );
  208. me.rpm.setValue( me.n1.getValue() );
  209. me.state.setIntValue(2);
  210. }
  211. else {
  212. me.reheat.setValue(0);
  213. me.state.setIntValue(3);
  214. interpolate(me.rpm,0,1);
  215. me.throttle_lever.setValue(0);
  216. }
  217. # me.smoking.setValue( ( me.damage.getValue() * 0.2 ) + ( me.rpm.getValue() * 0.009 ) );
  218. if ( me.rpm.getValue() < me.overspeed_rpm ) { me.overspeed.setBoolValue(0); }
  219. else { me.overspeed.setBoolValue(1); }
  220. }
  221. },
  222. fail_check: func {
  223. var x = rand();
  224. #print("Random Failure Generator: "~x);
  225. if ( me.damage.getValue() > 0.2 ) {
  226. me.stable.setBoolValue(0);
  227. }
  228. if ( me.damage.getValue() > 0.65 ) {
  229. me.serviceable.setBoolValue(0);
  230. }
  231. if (( me.damage.getValue() > 0.85 ) and ( me.running.getBoolValue() )) {
  232. me.explode(0.95);
  233. }
  234. if ( x < me.failure_prob ) {
  235. var sev = 0;
  236. if ( me.failure_prob < 0.01 ) { sev = ( rand() / 5 ); }
  237. else { sev = ( ( rand() + me.damage.getValue() ) / 4 ); }
  238. me.fail(sev);
  239. }
  240. if ( me.overspeed.getBoolValue() ) {
  241. me.failure_prob += (( rand() * 0.01 ) + ( ( ( me.rpm.getValue() * me.failure_prob ) / 1000 ) ));
  242. }
  243. if ( !me.stable.getBoolValue() and me.running.getBoolValue() ) {
  244. # Generate and add random damage
  245. }
  246. },
  247. fail: func (sev = 0.2) {
  248. print("Severity "~sev~" failure on "~ me.name );
  249. #me.damage.setValue( me.damage.getValue() += sev);
  250. var dx = ( me.damage.getValue() + sev );
  251. me.damage.setValue(dx);
  252. me.powerloss.setValue( dx * 4 );
  253. #interpolate(me.powerloss, ( dx * 4 ), 5);
  254. },
  255. explode: func (sev = 0.4) {
  256. print("Explosion in " ~ me.name );
  257. me.explosion.setValue(sev);
  258. interpolate( me.explosion, 0, ( sev * 1.15 ) );
  259. me.mpexplosion.setBoolValue(1);
  260. settimer( func {
  261. me.mpexplosion.setBoolValue(0);
  262. },2);
  263. if ( rand() < 0.85 ) { me.fire.setValue( ( sev + rand() ) * 0.5 ); }
  264. me.fail( sev );
  265. },
  266. };
  267. # Now do it!
  268. # var engine1 = Jet.new(0 , 0 , 0.01 , 5.21 , 4 , 4 , 0.05 , 1);
  269. #var engine2 = Jet.new(1 , 0 , 0.01 , 5.21 , 4 , 4 , 0.05 , 1);
  270. # engine1.init();
  271. # engine2.init();
  272. props.globals.initNode("/sim/autostart/started", 0, "BOOL");
  273. var eng1fuelon = func { setprop("/controls/engines/engine[0]/cutoff", 0); }
  274. var eng1fueloff = func { setprop("/controls/engines/engine[0]/cutoff", 1); }
  275. var eng2fuelon = func { setprop("/controls/engines/engine[1]/cutoff", 0); }
  276. var eng2fueloff = func { setprop("/controls/engines/engine[1]/cutoff", 1); }
  277. var eng1starter = func { setprop("/controls/engines/engine[0]/starter", 1); }
  278. var eng2starter = func { setprop("/controls/engines/engine[1]/starter", 1); }
  279. var eng1start = func {
  280. eng1fueloff();
  281. eng1starter();
  282. settimer(eng1fuelon, 2);
  283. }
  284. var eng2start = func {
  285. eng2fueloff();
  286. eng2starter();
  287. settimer(eng2fuelon, 2);
  288. };
  289. var engstart = func {
  290. settimer(eng1start, 2);
  291. settimer(eng2start, 8);
  292. }
  293. var engstop = func {
  294. eng1fueloff();
  295. eng2fueloff();
  296. }
  297. var autostart = func {
  298. var startstatus = getprop("/sim/autostart/started");
  299. if ( startstatus == 0 ) {
  300. gui.popupTip("Autostarting...");
  301. setprop("/sim/autostart/started", 1);
  302. setprop("/controls/electric/battery-switch", 1);
  303. settimer(engstart, 0.5);
  304. gui.popupTip("Starting Engines");
  305. }
  306. if ( startstatus == 1 ) {
  307. gui.popupTip("Shutting Down...");
  308. setprop("/sim/autostart/started", 0);
  309. eng1fueloff();
  310. eng2fueloff();
  311. }
  312. }
  313. var autostop = func {
  314. eng1fueloff();
  315. eng2fueloff();
  316. apufueloff();
  317. }