Scripts/separatedlasers.js |
"use strict";
this.name = "separatedlasers";
this.author = "Norby";
this.copyright = "2016 Norby";
this.description= "Lasers will not heat up faster if there is at least 30m space between multiple mounts";
this.licence = "CC BY-NC-SA 4.0";
//customizable properties
this.$Log = false; //log separated laser distances of ships when spawned
//worldscript events
this.startUpComplete = this.playerBoughtNewShip = function() {
this._Replace_Lasers(player.ship, this, false); //check and replace lasers to separated if possible
}
this.shipSpawned = function(ship) {
this._Replace_Lasers(ship, this, false); //check and replace NPC lasers to separated if possible
}
this.playerBoughtEquipment = function( equipment ) {
if( equipment.indexOf("EQ_WEAPON_") > -1 ) { //core lasers, laser cannons and other lasers in the future
//check and replace new laser to separated
//and replace back to basic laser if bought to not separated side
this._Replace_Lasers(player.ship, this, true);
}
}
//internal methods
this._Replace_Lasers = function(ship, w, refund) { //check and replace lasers to separated if possible
if( !ship || !ship.isValid ) return 0;
if( !w ) var w = worldScripts.separatedlasers;
var a = w._Separated_Lasers(ship, w);
if( a ) {
if( w.$Log ) log(w.name, ship.name+" Separated laser distances: fw:"+a[1]
+" aft:"+a[2]+" port:"+a[3]+" sb:"+a[4]);
// log(w.name, equipmentKey+" "+datakey+" "+ship.forwardWeapon+" "
// +ship.aftWeapon+" "+ship.portWeapon+" "+ship.starboardWeapon); //debug
var eq, eq1, len, m, multi = false, p = player.ship;
if( !ship.script ) ship.setScript("oolite-default-ship-script.js"); //for sure
var m = ship.script._cachedMultipleLasers; //read cached variable
if( !m ) {
var shipdata = Ship.shipDataForKey(ship.dataKey);
if( shipdata && shipdata["weapon_mount_mode"] == "multiply" ) m = 1;
else m = -1; //not multiple
ship.script._cachedMultipleLasers = m; //store into a cache variable
}
if( m == 1 ) multi = true; //a must for separation
if( ship.scriptInfo ) {
var si = parseInt( ship.scriptInfo.separated_lasers );
//separation is denied if shipdata contain script_info={separatedlasers=-1;};
//separation need an empty side mount if script_info contain separatedlasers=1;
if( si == -1 || si == 1 && ship.portWeapon && ship.starboardWeapon
//and need both side mounts stay without lasers if separatedlasers=2;
|| si == 2 && ( ship.portWeapon || ship.starboardWeapon ) ) {
multi = false; //deny separation
}
}
//replace back to single laser if bought a separated one to not separated side
//then replace single lasers to separated versions where there is enough space and money
//use the laser match to the number of mounts but max.5
//Dual, Triple, Quad or Broad Separated Pulse, Beam or Military Lasers,
//Sniper Guns and some Laser Cannons
if( ship.forwardWeapon ) {
eq = ship.forwardWeapon.equipmentKey;
if( multi ) len = ship.weaponPositionForward.length; else len = 1;
//replace back to basic laser if bought to not separated side
m = w._getMultiLevel(eq);
if( m > 1 && ( Math.min(5, len) != m || !a[1] || a[1] < w._space(eq) ) ) {
eq1 = eq.substr(0, eq.length-2);
//replace to single weapon without _2, _3, _4 or _5 at the end
if( !EquipmentInfo.infoForKey( eq1 ) ) eq1 = eq; //for sure
if( refund && ship == p ) w._refund( eq, eq1, len, true ); //no refund during flight
ship.forwardWeapon = eq1;
eq = eq1;
m = 1;
}
//replace single lasers to separated versions where there is enough space and money
if( m < 2 && len > 1 && a[1] && a[1] >= w._space(eq) ) {
eq1 = eq+"_"+Math.min(5, len); //max 5 (broadside)
if( EquipmentInfo.infoForKey( eq1 ) ) { //not all weapons are separable
if( refund && ship == p ) {
//no refund for NPCs and during flight (Sapper->Sniper Gun)
if( w._refund( eq, eq1, len, true ) )
ship.forwardWeapon = eq1;
} else ship.forwardWeapon = eq1;
}
}
}
if( ship.aftWeapon ) {
eq = ship.aftWeapon.equipmentKey;
if( multi ) len = ship.weaponPositionAft.length; else len = 1;
//replace back to basic laser if bought to not separated side
m = w._getMultiLevel(eq);
if( m > 1 && ( Math.min(5, len) != m || !a[2] || a[2] < w._space(eq) ) ) {
eq1 = eq.substr(0, eq.length-2);
//replace to single weapon without _2, _3, _4 or _5 at the end
if( !EquipmentInfo.infoForKey( eq1 ) ) eq1 = eq; //for sure
if( refund && ship == p ) w._refund( eq, eq1, len, true ); //no refund during flight
ship.aftWeapon = eq1;
eq = eq1;
m = 1;
}
//replace single lasers to separated versions where there is enough space and money
if( m < 2 && len > 1 && a[2] && a[2] >= w._space(eq) ) {
eq1 = eq+"_"+Math.min(5, len); //max 5 (broadside)
if( EquipmentInfo.infoForKey( eq1 ) ) { //not all weapons are separable
if( refund && ship == p ) {
//no refund for NPCs and during flight (Sapper->Sniper Gun)
if( w._refund( eq, eq1, len, true ) )
ship.aftWeapon = eq1;
} else ship.aftWeapon = eq1;
}
}
}
if( ship.portWeapon ) {
eq = ship.portWeapon.equipmentKey;
if( multi ) len = ship.weaponPositionPort.length; else len = 1;
//replace back to basic laser if bought to not separated side
m = w._getMultiLevel(eq);
if( m > 1 && ( Math.min(5, len) != m || !a[3] || a[3] < w._space(eq) ) ) {
eq1 = eq.substr(0, eq.length-2);
//replace to single weapon without _2, _3, _4 or _5 at the end
if( !EquipmentInfo.infoForKey( eq1 ) ) eq1 = eq; //for sure
if( refund && ship == p ) w._refund( eq, eq1, len, true ); //no refund during flight
ship.portWeapon = eq1;
eq = eq1;
m = 1;
}
//replace single lasers to separated versions where there is enough space and money
if( m < 2 && len > 1 && a[3] && a[3] >= w._space(eq) ) {
eq1 = eq+"_"+Math.min(5, len); //max 5 (broadside)
if( EquipmentInfo.infoForKey( eq1 ) ) { //not all weapons are separable
if( refund && ship == p ) {
//no refund for NPCs and during flight (Sapper->Sniper Gun)
if( w._refund( eq, eq1, len, true ) )
ship.portWeapon = eq1;
} else ship.portWeapon = eq1;
}
}
}
if( ship.starboardWeapon ) {
eq = ship.starboardWeapon.equipmentKey;
if( multi ) len = ship.weaponPositionStarboard.length; else len = 1;
//replace back to basic laser if bought to not separated side
m = w._getMultiLevel(eq);
if( m > 1 && ( Math.min(5, len) != m || !a[4] || a[4] < w._space(eq) ) ) {
eq1 = eq.substr(0, eq.length-2);
//replace to single weapon without _2, _3, _4 or _5 at the end
if( !EquipmentInfo.infoForKey( eq1 ) ) eq1 = eq; //for sure
if( refund && ship == p ) w._refund( eq, eq1, len, true ); //no refund during flight
ship.starboardWeapon = eq1;
eq = eq1;
m = 1;
}
//replace single lasers to separated versions where there is enough space and money
if( m < 2 && len > 1 && a[4] && a[4] >= w._space(eq) ) {
eq1 = eq+"_"+Math.min(5, len); //max 5 (broadside)
if( EquipmentInfo.infoForKey( eq1 ) ) { //not all weapons are separable
if( refund && ship == p ) {
//no refund for NPCs and during flight (Sapper->Sniper Gun)
if( w._refund( eq, eq1, len, true ) )
ship.starboardWeapon = eq1;
} else ship.starboardWeapon = eq1;
}
}
}
}
}
this._getMultiLevel = function(equipment) { //get the multiplication level of a given weapon
var m = 0;
var end = equipment.substr(-2, 2); //the last two characters of equipmentKey
if( end == "_2" && equipment != "EQ_WEAPON_CANNON_2" //except single Ingram 3838C8 Mini Cannon
&& equipment != "EQ_WEAPON_GATLING_LASER_2" ) m = 2; //and Gatling 2
if( end == "_3" && equipment != "EQ_WEAPON_CANNON_3" //except single Hassoni C38 Dual Cannon
&& equipment != "EQ_WEAPON_GATLING_LASER_3" ) m = 3; //and Gatling 3
if( end == "_4" && equipment != "EQ_WEAPON_CANNON_4" //except single Lance & Ferman Military Cannon
&& equipment != "EQ_WEAPON_GATLING_LASER_4" ) m = 4; //and Gatling 4
if( end == "_5" && equipment != "EQ_WEAPON_CANNON_5" //except single LF38 Twin Military Cannon
&& equipment != "EQ_WEAPON_GATLING_LASER_5" ) m = 5; //and Gatling 5
return( m );
}
this._Separated_Lasers = function(ship, w) {
//return false if no separated mount, else return array of sides
if( !w ) var w = worldScripts.separatedlasers;
var a = [];
a[1] = w._is_Separated_Mount(ship, 1, w); //forward
a[2] = w._is_Separated_Mount(ship, 2, w); //aft
a[3] = w._is_Separated_Mount(ship, 3, w); //port
a[4] = w._is_Separated_Mount(ship, 4, w); //starboard
// log(w.name, ship.name+" Laser distances: fw:"+a[1]+" aft:"+a[2]+" port:"+a[3]+" sb:"+a[4]);
if( !a[1] && !a[2] && !a[3] && !a[4] ) return false;
else return a; //array of min. distances at sides where lasers are separated, false at other sides
}
this._is_Separated_Mount = function(ship, side, w) { //return false if this side is not separated
if( !w ) var w = worldScripts.separatedlasers;
var d = w._mount_Distance(ship, side, w);
if( d < 30 ) return false;
else return d; //return min. distance if more than the minimally allowed for separated lasers
}
this._mount_Distance = function(ship, side, w) { //return 0 if only one mount, min. dist. if more.
if( !w ) var w = worldScripts.separatedlasers;
side = Math.floor(side);
var array;
if( !side || side <= 1 || side > 4 ) array = ship.weaponPositionForward;
else if( side == 2 ) array = ship.weaponPositionAft;
else if( side == 3 ) array = ship.weaponPositionPort;
else array = ship.weaponPositionStarboard;
var min = w._min_Distance(array);
return min;
}
this._min_Distance = function(array) { //calculate min. dist. in the given array of Vector3Ds
var min = 0;
if( array && array.length > 1 ) for(var i = 0; i < array.length; i++) {
for(var j = i + 1; j < array.length; j++) { //check against all remaining items
var d = 0;
if( array[i].distanceTo && array[j].distanceTo )
d = array[i].distanceTo(array[j]);
if( d > 0 && min == 0 ) min = d;
else if( min > 0 && d < min ) min = d;
// log(this.name, "d:"+d+"min:"+min+" a["+i+"]: "+array[i]+" a["+j+"]:"+array[j]);
}
}
// log(this.name, " array: "+array+" min.d:"+min);
return min;
}
this._refund = function(eq, eq1, length, msg) {
//refund weapon price, length is the size of multiple weapons array
var f = 1;
if( player.ship && player.ship.dockedStation ) {
var e = player.ship.dockedStation.equipmentPriceFactor;
if( e > 0 ) f = e;
}
if( 0 < oolite.compareVersion("1.83") ) length = 1; //no multiple weapons before Oolite 1.83
var refund = f * length * (EquipmentInfo.infoForKey( eq ).price
- EquipmentInfo.infoForKey( eq1 ).price)/10;
if( refund < 0 && player.credits < -1 * refund ) {
var m = EquipmentInfo.infoForKey( eq ).name
+ " is not the best in this mount, but you have not "
+ (-1*refund) + " credits to buy "
+ EquipmentInfo.infoForKey( eq1 ).name+".";
if(msg) player.consoleMessage(m, 10);
log(this.name, "Replace "+eq+" to "+eq1+" skipped, need "
+refund+"cr but you have "+player.credits+"cr only.");
return( false );
}
player.credits += refund;
var r = ", "+refund+" credits refunded.";
if( refund < 0 ) r = " for " + (-1*refund) + " credits.";
var m = EquipmentInfo.infoForKey( eq ).name
+ " is not the best in this mount, replaced to "
+ EquipmentInfo.infoForKey( eq1 ).name + r;
if(msg) player.consoleMessage(m, 10);
log(this.name, "Replace "+eq+" to "+eq1+", refund: "+refund+" cr");
return( true );
}
this._space = function(eq) { //how much space need between weapon positions to be separated
if( eq.indexOf("EQ_WEAPON_CANNON_5") > -1 //Twin Military Cannon
|| eq.indexOf("EQ_WEAPON_CANNON_10") > -1 //Plasma Ray
|| eq.indexOf("EQ_WEAPON_CANNON_12") > -1 //Twin Artillery Cannon
|| eq.indexOf("EQ_WEAPON_CANNON_EA") > -1 //Eco Artillery
|| eq.indexOf("EQ_WEAPON_ECO_REACTOR") > -1 //Eco Reactor
|| eq.indexOf("EQ_WEAPON_CANNON_SNIPER_GUN") > -1 ) //Sniper Gun
return(50); //need 50m
if( eq.indexOf("EQ_WEAPON_CANNON_HEAVY_SNIPER_GUN") > -1 ) //Heavy Sniper Gun
return(100); //need 100m
return(30); //all others need 30m
}
|