| Scripts/torustosun.js | "use strict";
this.name        = "torustosun";
this.author      = "Norby";
this.copyright   = "2014 Norbert Nagy";
this.licence     = "CC BY-NC-SA 4.0";
this.description = "Reach the Sun faster.";
//http://aegidian.org/bb/viewtopic.php?f=6&t=16704&p=223460#p223405
//-start at 1x when you leave the masslock of planet,
//-increasing exponentially between the planet and sun up to 8x,
//-multipliers over 2x need unpowered weapons,
//-fall down to the base value before the sun,
//-limited to the max value if far from both the sun and planet.
//-unpowered weapons provide 2x time forwarding at torus speeds.
//customizable properties
this.$MaxWithWeapons = 2; //chop the bonus to be able to catch Space Pizzas
this.$MaxTimeFw = 4; //time forwarding at max. multiplier (adjustment, not TAF)
this.$Messages = true; //show messages about the current speed (but no messages with CombatMFD regardless of this)
this.$MessagesWithCombatMFD = false; //send Torus multiplier messages with combatMFD also
this.$TimeFwWeaponsOff = 2; //default time forwarding with offline weapons
this.$MaxMultiplier = 8; //*32*400m/s (Asp) almost fit into the 5 digit NumericHUD
//internal properties, should not touch
this.$TimeFw = 1; //actual time forwarding, checked in CombatMFD
this.$TorusToSunBonus = 1; //current speed multiplier, checked in CombatMFD
this.$DBonus = ""; //the lastly displayed speed multiplier
this.$DMore = false; //the lastly displayed more need offline weapons message
this.$FCB = null; //framecallback
this.$FwSec = 0; //part of a second during forwarding
this.$NearestPlanet = null; //store the nearest planet between rechecks
this.$PrevEnergy = 0; //previous energy value of player
this.$Timer = null; //Timer for Torus speedup
this.$WED = null; //the worldscript of EscortDeck
this.$WFP = null; //store worldScripts.farplanets
//world script events
this.startUp = function() {
	this.$WED = worldScripts.escortdeck;
	this.$WFP = worldScripts.farplanets;
//	var n = worldScripts.numerichudv3;
//	if( n && n.version * 1 >= 3.24 ) this.$Messages = false;
	this.$Timer = new Timer(this, this._Timed.bind(this), 1, 0.25);
	this._StopTimer(); //pause timer
}
this.alertConditionChanged = function(newCondition, oldCondition) {
//     log("alertConditionChanged", newCondition  + "::" + oldCondition)
       if (newCondition == 1)       {
               this._StartTimer();
       } else  {
               this._StopTimer();
       }
}
this.shipWillDockWithStation = function() {
	this._StopTimer();
}
this.shipWillEnterWitchspace = function() {
	this._StopTimer();
}
this.shipWillExitWitchspace = function() {
	this._StartTimer(); //must start before Telescope FCBs!
}
this.shipWillLaunchFromStation = function() {
	this._StartTimer(); //must start before Telescope FCBs!
}
//TorusToSun functions
this._FCB = function( delta ) { //masslockcheck in this framecallback
	var b = this.$TorusToSunBonus;
	var ps = player.ship;
	if( !ps ) return; //player is died
//	log("TorusToSun", "speed: "+Math.round(ps.speed)+" velocity: "+Math.round(ps.velocity.magnitude())); //debug
	if( player.alertCondition > 1 || ps.speed < ps.maxSpeed * 31.9 //not in full torus
		|| this.$WFP && //FarPlanets OXP active
		( this.$WFP.$FarPlanetsSlowDown || this.$WFP.$FarPlanetsBonus > 1 )
		|| this._Proximity(this) ) //turn off near asteroids
		 this._TorusSlowDown(); //do not apply TorusToSun
	if( !this.$SlowDown && b > 1 ) { //currently travel at bonus speeds
		var f = ps.vectorForward;
		var s = ps.maxSpeed * 32;
		var t = this.$TimeFw - 1; //torus speed with time forwarding
		ps.position = ps.position.add( f.multiply( delta * s * ( t + b - 1 ) ) ); //apply speed bonus
        } else {
                if( isValidFrameCallback( this.$FCB ) )
                       removeFrameCallback( this.$FCB );
        }
}
this._NearestMass = function(skip) {
	var d = 100000000000000000000.0; //10^20m for sure
	var psp = player.ship.position;
	var nm = null;
	var p = system.planets;
	var len = p.length;
	for( var i = 0; i < len; i++ ) { //find the smallest distance
		var pl = p[i];
		if( pl != skip ) { //the second nearest if requested
			var s = psp.distanceTo( pl.position );
			if( d > s ) {
				d = s;
				nm = pl;
			}
		}
	}
	return( nm );
}
this._Proximity = function(ws) { //there is a similar function in TimeControl oxp, if changed then must change both!
	var s = player.ship.checkScanner(false);
	for( var i = 0; s && s.length > i; i++ ) {  //exclude escorts and telescopemarker
		if( ws.$WED && ws.$WED.$EscortDeckShip.indexOf(s[i]) == -1
			&& s[i].dataKey && s[i].dataKey != "telescopemarker" ) {
			return(true);
		}
	}
	return(false);
}
this._StartTimer = function() {
	this.$PrevEnergy = player.ship.maxEnergy;
	this.$FwSec = 0; //part of a second during forwarding
	if( this.$Timer ) {
		this.$Timer.start();
	}
}
this._StopTimer = function() {
	if( this.$Timer ) {
		this.$Timer.stop();
	}
	if( isValidFrameCallback( this.$FCB ) )
		removeFrameCallback( this.$FCB );
	this._TorusSlowDown(); //set bonus to 1
}
this._Timed = function() {
	var ps = player.ship;
	if( !ps || !ps.isValid ) return; //player died
	if( player.alertCondition == 1 && ps.speed > ps.maxSpeed * 31.9 ) {//Green Alert and Torus maxed
		this._TorusSpeedUp();
		if( !isValidFrameCallback( this.$FCB ) )
		        this.$FCB = addFrameCallback( this._FCB.bind(this) );
	}
}
this._TimeFw = function( bonus ) { //use time forwarding at maximal bonus if weapons off
	if( bonus == this.$MaxMultiplier && !player.ship.weaponsOnline ) return(true);
	return(false);
}
this._TorusSlowDown = function() { //slowdown from extreme speed to normal or Torus speeds
	if( this.$TorusToSunBonus <= 1 ) return; //need to avoid block Injector speeds
	this.$PrevEnergy = player.ship.energy;
	this.$TorusToSunBonus = 1; //the main thing for slowdown
	this.$DBonus = "";
	this.$DMore = false;
	this.$SlowDown = true; //flag to FCB
}
this._TorusSpeedUp = function() {
	var ps = player.ship;
	if( !ps || !ps.isValid || this.$WFP && //FarPlanets OXP active
		( this.$WFP.$FarPlanetsSlowDown || this.$WFP.$FarPlanetsBonus > 1 ))
		return;
	var bonus = 1;
	if( ps.equipmentStatus("EQ_TORUSTOSUN") == "EQUIPMENT_OK"
		&& system && system.planets && system.planets.length > 0
		&& !system.isInterstellarSpace && system.sun && system.sun.isValid
		&& !system.sun.hasGoneNova ) {
		this.$SlowDown = false;
	
		var co = 1000; //coefficient, larger value cause smaller speeds
		var mm = this.$MaxMultiplier;
		var sr = system.sun.radius;
		var pds = ps.position.distanceTo( system.sun.position ) - sr; //playerDistanceFromSun
		//check sun direction and apply gravity pullback, angle=0: aft, angle=PI: front
		var angle = ps.vectorForward.angleTo(ps.position.subtract(system.sun.position));
		sr = Math.min(sr, 200000); //max. 200km in the following formula
		//keep up the high speed much longer when approach the sun
		var min = pds / ( 10000 + ( 1 - angle / Math.PI ) * sr *
			Math.max( 0, 1 - pds / ( 10 * sr ) ) ); //no gravity pullback over 10 sun radius
		bonus = 1 + (mm - 1) * Math.min( 1, min * min / co ); //nonlinear calculation
		var nm = this._NearestMass();
		var nr = Math.max(nm.radius, 50000); //min. 50k to reduce speeds near small moons
		var pdp = ps.position.distanceTo( nm.position ) - 2 * nr; //playerDistanceFromPlanet
		min = pdp / nr;
		var b1 = 1 + (mm - 1) * Math.min( 1, min * min / co ); //nonlinear calculation
		bonus = Math.min(b1, bonus); //use the smaller bonus
		
		var nm2 = this._NearestMass(nm); //the second nearest mass
		if( nm2 ) {
			var nr2 = Math.max(nm2.radius, 50000); //min. 50k to reduce speeds near small moons
			var pdp2 = ps.position.distanceTo( nm2.position ) - 2 * nr2; //playerDistanceFromPlanet2
			min = pdp2 / nr2;
			var b2 = 1 + (mm - 1) * Math.min( 1, min * min / co ); //nonlinear calculation
			bonus = Math.min(b2, bonus); //use the smallest bonus
		}
//		log("TorusToSun", " bonus:"+bonus+" pdp:"+pdp+" pds:"+pds+" nm:"+nm); //debug
	}
	
	if( ps.weaponsOnline ) bonus = Math.min(bonus, this.$MaxWithWeapons);
	if( bonus > 1 ) { //show speed bonus, apply will happen in FCB
		var b = Math.round( bonus );
		if( this._TimeFw( bonus ) ) this.$TimeFw = this.$MaxTimeFw;
		else if( !ps.weaponsOnline ) this.$TimeFw = this.$TimeFwWeaponsOff; //2x
		else this.$TimeFw = 1; //no time forward with online weapons
		
		if( this.$TimeFw > 1 ) {
			var delta = 0.25; //0.25sec timer
			//calculate the bonus time plus add the previous remainder
			var sec = delta * ( this.$TimeFw - 1 ) + this.$FwSec;
//			log("TorusToSun", " bonus:"+bonus+" mm:"+mm+" sec:"+sec); //debug
			if( sec >= 1 ) {
				var maxsec = 2592000; //not allowed to add more sec in one step
				if( sec < maxsec ) clock.addSeconds( Math.floor( sec ) ); //add the integer part
				else {
					var sec2 = Math.floor( sec / maxsec );
					for(var i=0; i<sec2; i++) clock.addSeconds( maxsec );
					clock.addSeconds( sec - maxsec * sec2 );
				}
//				log("TorusToSun", this.$TimeFw+"x added "+sec+"s = "+(sec/86400)+" day"); //debug
				this.$FwSec = sec - Math.floor( sec ); //save the remainder
			} else this.$FwSec = sec;
			if( this.$PrevEnergy < ps.energy && ps.energy < ps.maxEnergy - 1 ) {
				//recharge speed up scaled with forwarding
				ps.energy +=  ( ps.energy - this.$PrevEnergy ) * sec / delta;
			}
		}
		if( this.$Messages && !this.$DMore && ps.weaponsOnline
			&& bonus == this.$MaxWithWeapons ) {
			this.$DMore = " - more need offline weapons";
			player.consoleMessage( "Torus " + b + "x" + this.$DMore, 5 );
		} else {
			if( this.$Messages && this.$DBonus != b && ( this.$MessagesWithCombatMFD
				|| ps.equipmentStatus("EQ_COMBATMFD") != "EQUIPMENT_OK" ) ) {
				player.consoleMessage( "Torus " + b + "x", 5 );
			}
		}
		if( bonus < this.$MaxWithWeapons) this.$DMore = false; //prevent repeated message
		this.$PrevEnergy = ps.energy;
		this.$TorusToSunBonus = bonus;
		this.$DBonus = b; //save last message to avoid repeat
	}  else this._TorusSlowDown(); //slowdown
}
 |