# Victor Engines - modified by Algernon from generic-yasim-engine.nas 
# -- a generic Nasal-based engine control system for YASim
# Version 1.0.0
#
# Copyright (C) 2011  Ryan Miller
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#

var UPDATE_PERIOD = 0; # update interval for engine init() functions

print("Loading YASim Engine Script...");

# jet engine class
var Jet =
{
	# creates a new engine object
	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,) 
	{
		# copy the Jet object
		var m = { parents: [Jet] };
		# declare object variables
		m.number = n;
		m.name = "Engine " ~ ( n + 1 );
		m.autostart_status = 0;
		m.autostart_id = -1;
		m.loop_running = 0;
		m.started = 0;
		m.starting = 0;
		m.idle_throttle = idle_throttle;
		m.max_start_n1 = max_start_n1;
		m.start_threshold = start_threshold;
		m.spool_time = spool_time;
		m.start_time = start_time;
		m.shutdown_time = shutdown_time;
		m.overspeed_rpm = 125; # 111
		m.failure_prob = 0.001;
		# create references to properties and set default values
		m.cutoff = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/cutoff", 1);
		m.cutoff.setBoolValue(!running);
		m.HPcock = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/HP-cock", 1);
		m.HPcock.setBoolValue(0);
		m.LPcock = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/LP-cock", 1);
		m.LPcock.setBoolValue(0);
		m.fuelboost = props.globals.getNode("controls/switches/boost-pump[" ~ n ~ "]", 1);
		m.fuelboost.setValue(0);
		m.n1 = props.globals.getNode("engines/engine[" ~ n ~ "]/n1", 1);
		m.n1.setDoubleValue(0);
		m.out_of_fuel = props.globals.getNode("engines/engine[" ~ n ~ "]/out-of-fuel", 1);
		m.out_of_fuel.setBoolValue(0);
		m.reverser = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/reverser", 1);
		m.reverser.setBoolValue(0);
		m.rpm = props.globals.getNode("engines/engine[" ~ n ~ "]/rpm", 1);
		m.rpm.setDoubleValue(running ? 100 : 0);
		m.running = props.globals.getNode("engines/engine[" ~ n ~ "]/running", 1);
		m.running.setBoolValue(running);
		m.serviceable = props.globals.getNode("engines/engine[" ~ n ~ "]/serviceable", 1);
		m.serviceable.setBoolValue(1);
		m.starter = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/starter", 1);
		m.starter.setBoolValue(0);
		m.state = props.globals.getNode("engines/engine[" ~ n ~ "]/state",1 );
		m.state.setIntValue(0);
		m.sip = props.globals.getNode("engines/engine[" ~ n ~ "]/start-in-progress", 1);
        m.sip.setBoolValue();
		m.throttle = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/throttle", 1);
		m.throttle.setDoubleValue(0);
		m.throttle_lever = props.globals.getNode("controls/engines/engine[" ~ n ~ "]/throttle-lever", 1);
		m.throttle_lever.setDoubleValue(0);
		m.overspeed = props.globals.getNode("engines/engine[" ~ n ~ "]/overspeed",1);
		m.overspeed.setBoolValue(0);
		m.dambase = props.globals.getNode("sim/damage/damage-zones/engine[" ~ n ~"]",1);
		m.damage = m.dambase.getNode("damage-norm", 1);
		m.damage.setValue(0);
		m.powerloss = m.dambase.getNode("power-loss-norm", 1);
		m.powerloss.setValue(0);
		m.smoking = m.dambase.getNode("smoke-norm", 1);
		m.smoking.setValue(0);
		m.fire = m.dambase.getNode("fire", 1);
		m.fire.setValue(0);
		m.stable = m.dambase.getNode("stable", 1);
		m.stable.setBoolValue(1);
		m.explosion = m.dambase.getNode("explosion", 1);
		m.explosion.setValue(0);
		m.mpexplosion = m.dambase.getNode("mp-explosion", 1);
		m.mpexplosion.setBoolValue(0);
		# return our new object
		return m;
	},
	
    # engine-specific autostart
	autostart: func
	{
		if (me.autostart_status)
		{
			me.autostart_status = 0;
			me.cutoff.setBoolValue(1);
		}
		else
		{
			me.autostart_status = 1;
			me.starter.setBoolValue(1);
			settimer(func
			{
				me.cutoff.setBoolValue(0);
			}, me.max_start_n1 / me.start_time);
		}
	},
	# creates an engine update loop (optional)
	init: func
	{
	    props.globals.getNode("engines/engine["~me.number~"]/serviceable",1).alias("/sim/failure-manager/engines/engine["~me.number~"]/serviceable");
		
		setlistener("/sim/damage/damage-zones/engine["~me.number~"]/damage-norm", func { me.fail_check(); } );
		
		if (me.loop_running) return;
		me.loop_running = 1;
		var loop = func
		{
			me.update();
			
			settimer(loop, UPDATE_PERIOD);
		};
		var fail_loop = func {
		     me.fail_check();
			 # Debug
			 # print("Failure Probability: "~ me.failure_prob);
			 settimer(fail_loop, 10);
			}
			
		settimer(loop, 0);
		settimer(fail_loop, 0);
	},
	# updates the engine
	update: func {

        me.smoking.setValue( ( me.damage.getValue() * 0.55 ) * ( me.rpm.getValue() * 0.009 ) + ( me.explosion.getValue() * 2 ) + ( me.fire.getValue() * 0.6 ) );
	
		
		
		if (me.running.getBoolValue() and !me.started)
		{
			me.running.setBoolValue(0);
			#me.state.setIntValue(0);
		}
		
		if ( !me.running.getBoolValue() and me.starter.getBoolValue() ) {
			 
			 if ( ( me.rpm.getValue() > 0.4 ) and ( me.rpm.getValue() <50 ) ) { 
			     me.sip.setBoolValue(1);
				 me.state.setIntValue(1);
				}
				
			else {
			     me.sip.setBoolValue(0);
				 me.state.setIntValue(0);
			    }
			}
	
		else {
		     me.sip.setBoolValue(0);
		}
		
		if (me.cutoff.getBoolValue() or !me.serviceable.getBoolValue() or me.out_of_fuel.getBoolValue())
		{
			var rpm = me.rpm.getValue();
			var time_delta = getprop("sim/time/delta-realtime-sec");
			if (me.starter.getBoolValue())
			{
				rpm += time_delta * me.spool_time;
				me.rpm.setValue(rpm >= me.max_start_n1 ? me.max_start_n1 : rpm);
				me.state.setIntValue(1);
			}
			else
			{
				rpm -= time_delta * me.shutdown_time;
				me.rpm.setValue(rpm <= 0 ? 0 : rpm);
				me.running.setBoolValue(0);
				me.throttle_lever.setDoubleValue(0);
				me.started = 0;
				
				if ( rpm > 0.5 ) {
				     me.state.setIntValue(3);
					}
				
				else {
				     me.state.setIntValue(0);
					}
			}
		 
		}
		elsif (me.starter.getBoolValue())
		{
			var rpm = me.rpm.getValue();
			if ( ( rpm >= 20 ) or  ( ( rpm >= me.start_threshold )  ) )
			{
				var time_delta = getprop("sim/time/delta-realtime-sec");
				rpm += time_delta * me.spool_time;
				me.rpm.setValue(rpm);
				if (rpm >= me.n1.getValue())
				{
					me.running.setBoolValue(1);
					me.starter.setBoolValue(0);
					me.started = 1;
				}
				else
				{
					me.running.setBoolValue(0);
				}
			}
		}
		elsif (me.running.getBoolValue())
		{
			me.throttle_lever.setValue(me.idle_throttle + (1 - me.idle_throttle) * me.throttle.getValue() - me.powerloss.getValue() );
			
			me.rpm.setValue( me.n1.getValue() );
			me.state.setIntValue(2);

			
			# me.smoking.setValue( ( me.damage.getValue() * 0.2 ) + ( me.rpm.getValue() * 0.009 ) );

             if ( me.rpm.getValue() < me.overspeed_rpm ) { me.overspeed.setBoolValue(0); }	 
			 else { me.overspeed.setBoolValue(1); }
		}
	},
	fail_check: func {
		 var x = rand();
		 #print("Random Failure Generator: "~x);
		 if ( me.damage.getValue() > 0.2 ) {
		     me.stable.setBoolValue(0);
			}
		 if ( me.damage.getValue() > 0.65 ) {
		     me.serviceable.setBoolValue(0);
			}
			
		 if (( me.damage.getValue() > 0.85 ) and ( me.running.getBoolValue() )) {
		     me.explode(0.95);
			}

		
		 if ( x < me.failure_prob ) {
		     var sev = 0;
			 if ( me.failure_prob < 0.01 ) { sev = ( rand() / 5 ); }
			 else { sev = ( ( rand() + me.damage.getValue() ) / 4 ); }
		     me.fail(sev);
			 
			}
			
		 if ( me.overspeed.getBoolValue() ) {
  		     me.failure_prob += (( rand() * 0.01 ) + ( ( ( me.rpm.getValue() * me.failure_prob ) / 1000 ) ));
			}
			
		 if ( !me.stable.getBoolValue() and me.running.getBoolValue() ) {
		     # Generate and add random damage

			}
		},
	fail: func (sev = 0.2) { 
         print("Severity "~sev~" failure on "~ me.name );
		 #me.damage.setValue( me.damage.getValue() += sev);
	     var dx = ( me.damage.getValue() + sev );
		 me.damage.setValue(dx);
		 me.powerloss.setValue( dx * 4 );
		 #interpolate(me.powerloss, ( dx * 4 ), 5);				 
	    },
    explode: func (sev = 0.4) {
	     print("Explosion in " ~ me.name );
	     me.explosion.setValue(sev);
		 interpolate( me.explosion, 0, ( sev * 1.15 ) );
		 me.mpexplosion.setBoolValue(1);
		 settimer( func {
		     me.mpexplosion.setBoolValue(0);
			},2);
		 if ( rand() < 0.85 ) { me.fire.setValue( ( sev + rand() ) * 0.5 ); }
		 me.fail( sev );
		},
};

# Now do it!

   # var engine1 = Jet.new(0 , 0 , 0.01 , 5.21 , 4 , 4 , 0.05 , 1);
    #var engine2 = Jet.new(1 , 0 , 0.01 , 5.21 , 4 , 4 , 0.05 , 1);

  # engine1.init();
  # engine2.init();


props.globals.initNode("/sim/autostart/started", 0, "BOOL");

var eng1fuelon = func { setprop("/controls/engines/engine[0]/cutoff", 0); }
var eng1fueloff = func { setprop("/controls/engines/engine[0]/cutoff", 1); }

var eng2fuelon = func { setprop("/controls/engines/engine[1]/cutoff", 0); }
var eng2fueloff = func { setprop("/controls/engines/engine[1]/cutoff", 1); }

var eng1starter = func { setprop("/controls/engines/engine[0]/starter", 1); }
var eng2starter = func { setprop("/controls/engines/engine[1]/starter", 1); }

var eng1start = func {
   eng1fueloff();
   eng1starter();
   settimer(eng1fuelon, 12);
}

var eng2start = func {
   eng2fueloff();
   eng2starter();
   settimer(eng2fuelon, 12);
};

var engstart = func {
   settimer(eng1start, 2);
   settimer(eng2start, 8);
}

var engstop = func {
   eng1fueloff();
   eng2fueloff();
}

var autostart = func {
   var startstatus = getprop("/sim/autostart/started");
   if ( startstatus == 0 ) {
      gui.popupTip("Autostarting...");
	  setprop("/sim/autostart/started", 1);
      setprop("/controls/electric/battery-switch", 1);
      settimer(engstart, 0.5);
	  gui.popupTip("Starting Engines");
	  }
   if ( startstatus == 1 ) {
      gui.popupTip("Shutting Down...");
      setprop("/sim/autostart/started", 0);
	  eng1fueloff();
      eng2fueloff();
   }
}

var autostop = func {
   eng1fueloff();
   eng2fueloff();
   apufueloff();
}

print("                      ...done.");
   
