| Scripts/timecontrol.js | "use strict";
this.name	= "timecontrol";
this.author	= "Norby";
this.copyright	= "2015 Norby";
this.description= "Set and clear Time Acceleration in Green and Red alert, etc. Need developer release of Oolite.";
this.licence	= "CC BY-NC-SA 4.0";
//customizable properties
this.$GreenTAF = 1; //Time Acceleration Factor in green alert (max. 16, 1=turn off)
this.$InjectorsTAF = 2; //maximal Time Acceleration Factor with Injectors
this.$TorusTAF = 4; //maximal Time Acceleration Factor with Torus Jump Drive
this.$TorusTAFWithTorusToSun = 1; //prevent addition with time forwarding in TTS
this.$MinFPS = 20; //maintain at least this FPS
//internal properties, should not touch
this.$ED = null; //the worldscript of EscortDeck
this.$FCB = null; //FrameCallBack pointer
this.$ON = false; //TAF set over 1, needed to set back to 1 after releasing Injectors
this.$PrevFPS = this.$MinFPS;
this.$Timer = null;
this.$Wormholes = []; //store the last wormholes to stop time once only at a new wormhole
//worldscript events
this.startUp = function() {
	timeAccelerationFactor = 1;
	if( worldScripts.torustosun ) this.$TorusTAF = this.$TorusTAFWithTorusToSun;
	this.$ON = false;
	this.$ED = worldScripts.escortdeck;
}
/* old solution without FCB
this.alertConditionChanged = function(newCondition, oldCondition) {
   if( newCondition == 3 || player.alertHostiles ) { //red alert
        timeAccelerationFactor = 1;
   } else if( newCondition == 1 ) { //green alert
      timeAccelerationFactor = this.$GreenTAF;
   }
}
*/
this.shipDockedWithStation = function() {
        timeAccelerationFactor = 1; //as in TAF Reset OXP
	this.$ON = false;
        if( isValidFrameCallback( this.$FCB ) )
		removeFrameCallback( this.$FCB );
	if( this.Timer ) {
		this.$Timer.stop();
		delete this.$Timer;
	}
}
this.shipLaunchedFromStation = function() {
	this.$PrevFPS = this.$MinFPS;
	if( !isValidFrameCallback( this.$FCB ) )
		this.$FCB = addFrameCallback( this.$TimeControl_FCB );
	if( !this.$Timer ) this.$Timer = new Timer(this, this.$Timed.bind(this), 4, 4);
}
//TimeControl methods
this.$TimeControl_FCB = function( delta ) { //FrameCallBack to adjust TAF based on FPS
	var ws = worldScripts.timecontrol;
	var minfps = ws.$MinFPS; //maintain at least this FPS
	var ps = player.ship;
	if( !ps || player.alertCondition > 2 ) { //Red Alert
		timeAccelerationFactor = 1;
		ws.$ON = false;
//		log(ws.name, "Off by red alert");
	} else {
		//max. TAF adjusted to keep FPS over minfps
		var taf = timeAccelerationFactor;
		var fps = 100;
		if( delta > 0 ) fps = taf / delta;
		fps = ( ws.$PrevFPS + fps ) / 2; //average needed to skip accidentally zero delta
		ws.$PrevFPS = fps;
		if( fps < minfps ) {
			if( taf > 1 && ws.$ON ) {
				timeAccelerationFactor--;
//				log(ws.name, "Reduced by minfps, fps:"+fps);
			}
		} else {
			if ( ps.speed > ps.maxSpeed * 7 + 10 ) { //Torus
				if( ws.$TimeControl_Proximity(ws) ) { //turn off near asteroids
					timeAccelerationFactor = 1;
					ws.$ON = false;
//					log(ws.name, "Off by proximity");
				} else if( ws.$TorusTAF > 1 ) {
					if( taf < ws.$TorusTAF ) timeAccelerationFactor++;
					else if( taf > ws.$TorusTAF && ws.$ON )
						timeAccelerationFactor = ws.$TorusTAF;
					ws.$ON = true;
				}
			} else if ( ps.speed > ps.maxSpeed + 10 ) { //Injector
				if( taf < ws.$InjectorsTAF ) timeAccelerationFactor++;
				else if( taf > ws.$InjectorsTAF && ws.$ON )
					timeAccelerationFactor = ws.$InjectorsTAF;
				ws.$ON = true;
			} else if ( player.alertCondition == 1 ) { //Green alert
				if( taf < ws.$GreenTAF ) timeAccelerationFactor++;
				else if( taf > ws.$GreenTAF && ws.$ON )
					timeAccelerationFactor = ws.$GreenTAF;
				ws.$ON = true;
			} else if( ws.$ON ) { //turn off TAF only if turned on by this script
				timeAccelerationFactor = 1;
				ws.$ON = false;
//				log(ws.name, "Off by condition");
			}
		}
	}
//	log(ws.name, "ON:"+ws.$ON+" "+timeAccelerationFactor+"x TAF "+Math.round(timeAccelerationFactor/delta)+"FPS "+Math.round(ws.$PrevFPS)+"FPSavg "+Math.round(ps.speed)+" speed");
}
this.$TimeControl_Proximity = function(ws) {
	var s = player.ship.checkScanner(false);
	for( var i = 0; s && s.length > i; i++ ) {  //exclude escorts and telescopemarker
		if( ws.$ED && ws.$ED.$EscortDeckShip.indexOf(s[i]) == -1
			&& s[i].dataKey && s[i].dataKey != "telescopemarker" ) {
			return(true);
		}
	}
	return(false);
}
this.$Timed = function() {
	function $isWormhole(entity) {
		return(entity.isWormhole);
	}
	
	if( timeAccelerationFactor > 1 ) { //stop if a new Wormhole is opened near
//		var s = ps.checkScanner(false); - does not work, no wormhole in the list
		var s = system.filteredEntities(this, $isWormhole, player.ship, player.ship.scannerRange);
		for( var i = 0; s && s.length > i; i++ ) {
//			log(s[i].name+" "+s[i].isWormhole);//debug
			if( s[i] && s[i].isValid && s[i].isWormhole
				&& this.$Wormholes.indexOf(s[i]) == -1 ) {
				this.$Wormholes.push(s[i]);
				timeAccelerationFactor = 1;
				this.$ON = false;
				log(this.name, "Off by wormhole");
			}
		}
	}
}
 |