| Scripts/variablemasslock.js |
this.name = "variablemasslock";
this.author = "Norby";
this.copyright = "2015 Norby";
this.description= "Variable masslocks based on object masses";
this.licence = "CC BY-NC-SA 4.0";
/* (function () { // variablemasslock IIFE to run prior to reloading entire script
var vm = worldScripts.variablemasslock;
vm.$VMStopTimer(vm);
})() // */
/* (function () { // variablemasslock IIFE to run after reloading entire script
var vm = worldScripts.variablemasslock;
vm.$VMStartTimer(vm);
})() // */
(function(){
"use strict";
//internal properties, should not touch
this.$VMActive = false; //there is at least a ship with changed scanClass to prevent masslock
this.$VMFCB = null; //FrameCallBack pointer
this.$VMRocks = []; //store asteroids, bouys and cargo boxes with changed scanClass
// - causes masslock (to avoid collision); those close & dead ahead
this.$VMShips = []; //store ships with changed scanClass and its original scanClass
// - prevents masslock until breach reduced range
this.$VMTimer = null; //Timer for detect new ships
//worldscript events
this.startUp = function() {
// this.$WSED = worldScripts.escortdeck;
}
this.alertConditionChanged = function alertConditionChanged(newCondition /*, oldCondition */) {
var that = alertConditionChanged;
var vm = (that.vm = that.vm || worldScripts.variablemasslock);
var fcb = vm.$VMFCB;
if( fcb ) {
if( isValidFrameCallback( fcb ) ) {
removeFrameCallback( fcb );
}
vm.$$VMFCB = null;
}
if( newCondition == 1 ) { //green alert
vm.$VMFCB = addFrameCallback( vm.$VM_FCB.bind(vm) );
} else { //other than green alert
vm.$VMActive = false;
vm.$VM_Restore();
if( newCondition == 2 ) vm.$VM_Timed.bind(vm);
}
}
this.shipDockedWithStation = function() {
this.$VM_StopTimer(this);
}
this.shipWillLaunchFromStation = function() {
this.$VM_StartTimer(this);
}
//VariableMasslock methods
this.$Range = function(mass) { //callable from other scripts
return( mass * 0.02 + 17000 ); //small masslock radius of this ship
}
this.$VM_FCB = function VM_FCB() { //FrameCallBack in green alert
var that = VM_FCB;
var vm = (that.vm = that.vm || worldScripts.variablemasslock);
//detect if a ship with changed scanClass is arrived within the shortened masslock range
//and restore scanClasses to go out from green alert
var ps = player.ship;
if( !ps || !ps.isValid || !vm.$VMActive ) return;
var vmShips = vm.$VMShips;
if( vmShips ) {
var ppos = ps.position;
for( var i = 0, len = vmShips.length; i < len; i++ ) {
var sData = vmShips[i];
if( sData ) {
var ship = sData[0];
if( ship && ship.isValid && sData[2] > ship.position.distanceTo( ppos ) ) {
ship.scanClass = sData[1]; //end of green alert as ship is within its radius
// - restoring class will cause masslock
ship.scannerDisplayColor1 = null; //restore default color
return;
}
}
}
}
}
this.$VM_Restore = function VM_Restore() { //restore scanClasses of changed ships to its original scanClass
var that = VM_Restore;
var vm = (that.vm = that.vm || worldScripts.variablemasslock);
var arrays = (that.arrays = that.arrays || vm.$VM_arrays);
var vmShips = vm.$VMShips;
if( vmShips ) {
for( var i = 0, len = vmShips.length; i < len; i++ ) {
var sData = vmShips[i];
if( sData ) {
var ship = sData[0];
if( ship && ship.isValid ) {
ship.scanClass = sData[1]; //restore original scanClass
ship.scannerDisplayColor1 = null; //restore default color
}
vmShips[i] = arrays.pop( sData );
}
}
}
vmShips.length = 0; // clear & re-use array
}
this.$VM_Rocks = function VM_Rocks(flush) {
var that = VM_Rocks;
var vm = (that.vm = that.vm || worldScripts.variablemasslock);
var arrays = (that.arrays = that.arrays || vm.$VM_arrays);
function restore( ship, details ) {
ship.scanClass = details[1];
ship.scannerDisplayColor1 = null; //restore default color
return arrays.pop( details ); //remove array from the array
}
var ps = player.ship;
if( !ps || !ps.isValid ) return;
var ppos = ps.position;
var vmRocks = vm.$VMRocks; //restore changed asteroids
for( var i = 0, len = vmRocks.length; i < len; i++ ) {
var rData = vmRocks[i];
if( rData ) {
var rock = rData[0]; //Asteroids do not masslock over the given distance
if( rock && rock.isValid ) {
if( flush !== undefined ) {
vmRocks[i] = restore(rock, rData);
} else {
var dist = rock.position.distanceTo( ppos );
var angle = ps.heading.angleTo( rock.position.subtract(ppos) );
if( dist >= ps.speed || angle >= 0.1 ) {
// log( vm.name, 'VM_Rocks, ' + rock.name+" "+rock.scanClass+" "+dist+"m "+angle+"rad" ); //debug
vmRocks[i] = restore(rock, rData);
}
}
} else {
vmRocks[i] = arrays.pop( rData ); //remove array from the array
}
}
}
if( flush !== undefined ) {
vmRocks.length = 0; // clear & re-use array
}
}
this.$VM_StartTimer = function VM_StartTimer() {
var that = VM_StartTimer;
var vm = (that.vm = that.vm || worldScripts.variablemasslock);
if( vm.$VMTimer ) {
vm.$VM_StopTimer();
}
vm.$VMTimer = new Timer(vm, vm.$VM_Timed.bind(vm), 1, 0.31);
}
this.$VM_StopTimer = function VM_StopTimer() {
var that = VM_StopTimer;
var vm = (that.vm = that.vm || worldScripts.variablemasslock);
let timer = vm.$VMTimer;
if( timer ) {
if( timer.isRunning ) {
timer.stop();
}
vm.$VMTimer = null;
}
vm.$VM_Restore(); //restore ship scanClasses in variable masslock range
vm.$VM_Rocks(true); //restore changed asteroids
}
this.$VM_Timed = function VM_Timed() { //detect if there is a ship on scanner over the shortened
// masslock range and change scanClass to do not masslock
var that = VM_Timed;
var arrays = (that.arrays = that.arrays || this.$VM_arrays);
var ps = player.ship;
if( !ps || !ps.isValid ) return;
var ppos = ps.position;
this.$VM_Restore(this); //restore ship scanClasses in variable masslock range
this.$VM_Rocks(this); //restore asteroids over given range
if( player.alertCondition > 2 ) return; //no check in red alert
var f = ps.checkScanner(false);//much faster than filteredEntities
// var f = system.filteredEntities(this, this._isShip, ps, ps.scannerRange); //slow
var vm = true; //variable masslock active
var vmShips = this.$VMShips; //save changed ships
if( f ) {
var vmRocks = this.$VMRocks; //save changed asteroids
for( var i = 0, len = f.length; vm && i < len; i++ ) {
var ent = f[i];
if( ent.hasOwnProperty('$TelescopeTarget') ) // telescope's marker is a tiny ship that normally doesn't masslock
continue;
if( ent && ent.isValid ) {
var tpos = ent.position;
var t2p = tpos.subtract(ppos);
var dist = t2p.magnitude();
// log( this.name, 'VM_Timed, ' + ent.name+" "+ent.scanClass+" "+dist+"m"); //debug
var rock = false;
var scan = ent.scanClass;
if( scan == "CLASS_BUOY" || scan == "CLASS_CARGO" || scan == "CLASS_MINE" ||
scan == "CLASS_NO_DRAW" || scan == "CLASS_ROCK" )
rock = true;
if( rock && dist < ps.speed
&& ps.heading.angleTo( t2p ) < 0.1 ) {
vmRocks.push( arrays.pushRock(ent, scan) ); //save
ent.scanClass = "CLASS_STATION"; //Asteroids, buoys, etc. do masslock
ent.scannerDisplayColor1 = [0.9, 0.9, 0.9]; //keep at gray
} else if( !rock ) {
var mlDist = this.$Range( ent.mass ); //small masslock radius of this ship
if( mlDist < dist ) {
vmShips.push( arrays.pushShip(ent, ent.scanClass, mlDist) ); //save masslock radius for FCB
} else {
this.$VMActive = vm = false; //there is a ship within small radius
}
}
}
}
}
if( vm && vmShips && vmShips.length > 0 ) {
//change scanClasses only if all ships are out of radius, cause green alert
this.$VMActive = true;
for( var i = 0, len = vmShips.length; i < len; i++ ) {
var ship = vmShips[i][0];
if( ship && ship.isValid ) {
var scan = ship.scanClass, dColor;
if( scan == "CLASS_MILITARY" || scan == "CLASS_POLICE" )
dColor = [0.5, 0.0, 0.5]; //purple
else if( scan == "CLASS_MISSILE" )
dColor = [0.0, 0.9, 0.9]; //darker cyan
else if( scan == "CLASS_STATION" )
dColor = [0.0, 0.9, 0.0]; //darker green
else if( scan == "CLASS_THARGOID" )
dColor = [0.9, 0.0, 0.0]; //darker red
else dColor = [0.7, 0.7, 0]; //darker yellow
ship.scanClass = "CLASS_BUOY";
ship.scannerDisplayColor1 = dColor;
}
}
// log(this.name, 'VM_Timed, ' + vmShips); //debug
}
}
this.$VM_cache = function() {
this.cache = [];
}
this.$VM_cache.prototype.pushRock = function( rock, scanClass ) {
// log(this.name, '$VM_cache.pushRock, cache: ' + this.cache.length + ', rock: ' + rock + ', scanClass: ' + scanClass); //debug
var array = this.cache.length > 0 ? this.cache.pop() : [];
array[0] = rock;
array[1] = scanClass;
return array;
}
this.$VM_cache.prototype.pushShip = function( ship, scanClass, radius ) {
// log(this.name, '$VM_cache.pushShip, cache: ' + this.cache.length + ', ship: ' + ship + ', scanClass: ' + scanClass + ', radius: ' + radius); //debug
var array = this.cache.length > 0 ? this.cache.pop() : [];
array[0] = ship;
array[1] = scanClass;
array[2] = radius;
return array;
}
this.$VM_cache.prototype.pop = function( array ) {
if( !array || !Array.isArray( array ) ) {
log(this.name, '$VM_cache.pop, got an invalid arg: ' + array);
return;
}
array.length = 0;
this.cache.push( array );
// log(this.name, '$VM_cache.pop, cache: ' + this.cache.length); //debug
return null; // convenience return
}
this.$VM_arrays = new this.$VM_cache();
}).call(this);
// only use the following line instead of the preceding one if you're loading
// this entire script (from line 20) into the debug console
// }).call(worldScripts.variablemasslock);
/* http://wiki.alioth.net/index.php/Shipdata.plist#scan_class
Will alter the model's appearance on the IFF system. If this line is omitted, it will usually become by default a standard ship entity (CLASS_NEUTRAL), appearing as a yellow flag on the radar (red if hostile to the player), but may be given a different scan class if added with other roles. There are other options.
! CLASS_BUOY - green/yellow on scanner, will rotate in idle state, does not masslock
! CLASS_CARGO - white on scanner, can be scooped, does not masslock
CLASS_MILITARY - purple on scanner, better pilots, will not attack other military ships, flashes purple/magenta if hostile to player
CLASS_MISSILE - cyan on scanner, will not avoid collisions
CLASS_POLICE - purple on scanner, will not attack other police ships, legal penalties for attacking, never has bounty, flashes purple/magenta if hostile to player
! CLASS_ROCK - white on scanner, launched defense ships do not inherit scan class, does not masslock
CLASS_STATION - green on scanner, launched defense ships do not inherit scan class
CLASS_THARGOID - green/red on scanner, considered hostile to any non-thargoid ship
! CLASS_NO_DRAW - invisible on scanner, cannot be targeted by missiles, does not masslock
! CLASS_MINE - red/yellow on scanner, automatically set on mines launched by player to override existing scan class, does not masslock
(This property was called "scanClass" before Oolite 1.74.) Scan classes marked as "does not masslock" will masslock the player anyway if they are hostile to the player (as condition will be Red)
Scripts can define custom colours for ships on the IFF system so ships may have a scanner appearance different to the default for their scan class.
Example:
"scan_class" = "CLASS_ROCK";
Developer Note
Oolite uses scan_class internally to determine the behaviour of some ships (particularly with regard to who may shoot whom without incurring legal penalties). Bear this in mind and don't allocate CLASS_POLICE or CLASS_THARGOID to ships lightly!
*/
|