| Scripts/assassins_shipset_pack.js | "use strict";
this.name			= "Assassin_shipset_pack";
this.author			= "Rustem";
this.copyright		= "2017";
this.description	= "worldscript for Assassin shipset pack";
this.licence		= "CC BY-NC-SA 4.0";
this._shipSpawnOverride = false;
// Addition to GC MostWanted list delevoped for assassin role. Current GC MostWanted v0.7.
this.logging = false;        // false/true
this._debug = true;          // debug for GC MW
this._debug_AI = false;      // logging setAI
this._debug_Bty = false;     // logging setBounty
this._debug_Wpn = false;     // logging setWeapon
this._debug_Eqp = false;     // logging setEquipment
//this._ai_Drone = null;		// logging of AI State of Drone
//this._ai_Tharglet = null;	// logging of AI State of Tharglet
this._sdc_Installed = false;  // indicates whether Station Dock Control OXP is installed
this._gcm_ht_Installed = false; // indicates whether GalCop Missions OXP is installed (v0.5.2)
// var used in the ship script
this._safeSystem = [];
this._safeDangerous = [];     // list of safe/dangerous systems (array of dictionarys, having "id"-int and "dangerous"-array of ints)
this._ht_amount = 0;	      // amount ship from GalCopBB_HitTeams
this._mw_count = 0;           // count ship in the actual spawn state
this._mw_escorts = null;      // allow spawn escorts
// Addition of the extra missiles delevoped for Armoury OXP v1.13 and more.
this._extraMissiles = [];	  // array for extra missiles
this._weaponNoneSet = { // blacklist for weapons unchanged // ships with special weapon specification (ex: Sniper Guns)
	"asp_sg_Assassin_AP_shipset": "WEAPON_NONE",
	"asp_sg_Hunter_AP_shipset": "WEAPON_NONE",
	"constrictor_sg_Assassin_AP_shipset": "WEAPON_NONE",
	"constrictor_sg_Hunter_AP_shipset": "WEAPON_NONE",
	"dttwraith_Pirate_AP_shipset": "WEAPON_NONE",
	"dttwraith_Hunter_AP_shipset": "WEAPON_NONE",
	"ferdelance_sg_Assassin_AP_shipset": "WEAPON_NONE",
	"ferdelance_sg_Hunter_AP_shipset": "WEAPON_NONE"
}
this._aftWeaponNone = { // from shipKey specification, blacklist for aft weapons unchanged
	"stealth_Escort_AP_shipset": "WEAPON_NONE",
	"stealth_Raider_escort_AP_shipset": "WEAPON_NONE",
	"cb68_pitviper2_AP_shipset": "WEAPON_NONE",
	"cb68_pitviper2_HunterAP_shipset": "WEAPON_NONE"
}
/* The global level of bias in weapon selection. A few useful // copy from populator
 * threshold values if modifying this:
 *
 * 0: default weapon selection
 *
 * 0.2: above this military lasers start being granted to rare ships
 *
 * 1.2: above this aft military lasers start appearing; forward
 * military/aft beam is common
 *
 * -0.8: no ships have aft beam laser; forward beam is rare
 *
 * -1.8: no ships have beam lasers
 *
 * A few ships (e.g. police ships) do not have variable lasers and
 * are not affected by this setting.
 */
this.$weaponLevelBias = 0;
/* World script event handlers */
this.startUpComplete = function startUpComplete() {
	var mw = worldScripts.BountySystem_MostWanted; // worldScripts["BountySystem_MostWanted"]
	if (mw) this._mw_Installed = true;
	var ht = worldScripts.GalCopBB_HitTeams;
	if (ht) {
		this._gcm_ht_Installed = true;
	}
	if (worldScripts.StationDockControl) {
		this._sdc_Installed = true;
		// WAIT: Disable, need enable?
		// worldScripts.StationDockControl._propertiesToKeep.push("_mostWanted");
	}
	// check wanted records
	if (this._mw_Installed) {
		this._leader = [];
		this._wantedGroup = [];
		this._groupName = "";
		this._wanted_amount = 0;
		if (mw._wanted.length === 0) {
			log(this.name, "First start: GC MostWanted")
		} else {
			this.$updateMWData()
		}
	}
	// sets extra missiles
	if (worldScripts.CT_Script) {
		this._armInstalled = true;
		this._extraMissiles.push("EQ_NPC_CD_MINE", "EQ_NPC_KD_MINE") // for "EQ_NPC_CT_MINE" will be check a ship mass or level
		// based on EQ_CT_MINE, EQ_CDRONE_LAUNCHER_MINE, EQ_KDRONE_LAUNCHER_MINE / EQ_ATDRONE_LAUNCHER_MINE
	} else {
		this._extraMissiles.push("EQ_HARDENED_MISSILE")
	}
	if (worldScripts.fighters) {
		this._fightersInstalled = true;
		this._extraMissiles.push("EQ_NPC_SWARM_MISSILE") // based on fighters-swarm
	}
}
this.playerWillEnterWitchspace = function playerWillEnterWitchspace() {
	if (this._mw_Installed) {
		this._mw_count = 0; // count ship in the actual spawn state
		this._mw_escorts = null; // allow spawn escort	
		// TEST: worldScripts.BountySystem_MostWanted._pending.length = 0;
		//worldScripts.BountySystem_MostWanted.$lookForPendingRecords(); // TEST: added before fully check in GC MW.
	}
	if (this._gcm_ht_Installed) this.$updateHTData();
}
this.shipLaunchedFromStation = this.shipExitedWitchspace = function shipExitedWitchspace() {
	if (this._mw_Installed) this.$updateMWData(); 
	//if (this._gcm_ht_Installed) this.$updateHTData();
	var n = Math.floor(10 + 1.0 * Math.log(worldScripts["oolite-populator"].$repopulatorFrequencyOutgoing.assassins)); //8..-inf // oolite stats:7..2
	log(this.name, "ASPack: Factor(FreqOutgoingAssassins): " + n);
}
/* Ship addition functions for GC MW list*/
this.$updateMWData = function () {
	// delay need for set dta.shipName and etc.
	var mw = worldScripts.BountySystem_MostWanted;
	this._wanted_amount = 0;
	for (var i = 0; i < mw._wanted.length; i++) {
		var wanted = mw._wanted[i];
		if (wanted.shipDataKey.indexOf('_AP_shipset') > -1) {
			this._wanted_amount++;
		}
	}
	this._wantedGroup.length = 0;
	if (this._wanted_amount > 0) {
		log(this.name, "ASPack: Amount of the ships in GC MW list: " + this._wanted_amount);
	}
}
/* Ship addition functions for in GC_HitTeams list*/
this.$updateHTData = function () {
	var ht = worldScripts.GalCopBB_HitTeams;
	this._ht_ships = [];
	if (ht._hitTeams && ht._hitTeams.length > 0) {
		this._ht_amount = 0;
		for (var i = 0; i < ht._hitTeams.length; i++) {
			for (var j = 0; j < ht._hitTeams[i].ships.length; j++) {
				var s = ht._hitTeams[i].ships[j].dataKey;
				if (s.indexOf('_shipset') > -1) { // '_AP_shipset' / '_shipset'
					this._ht_amount++;
					this._ht_ships.push(s);
				}
			}
		}
		if (this._ht_amount > 0) {
			log(this.name, "ASPack: Amount of the ships in GC HT list: " + this._ht_amount);
		}
	}
}
/* Ship addition functions */
this._setBountyToShip = function (ship) {
	var random = Math.random;
	var s = ship;
	var pr = s.primaryRole;
	var sc = s.script;
	var k = s.dataKey;
	var bounty, ai;
	var g = s.group;
	// for ensure set correctly JS AI, but not reset for custom AI.plist
	if (s.AI === "nullAI.plist" && s.AIScript) {
		var js = true;
		var nm = s.AIScript.name;
	}
	// autoAImap.plist	
	if (pr.indexOf('assassin') > -1) {
		if (js && nm.indexOf("Assassin") < 0) ai = "oolite-assassinAI.js";
		bounty = true;
	} else if (pr.indexOf('hunter') > -1) {
		if (g && g.leader && s == g.leader) {
			if (js && nm.indexOf("Bounty Hunter") < 0) ai = "oolite-bountyHunterLeaderAI.js";
		} else {
			if (js && nm.indexOf("Bounty Hunter") < 0) ai = "oolite-bountyHunterAI.js";
		}
		bounty = null;
	} else if (pr.indexOf('courier') > -1 || pr.indexOf('trader') > -1) {
		if (js && nm.indexOf("Trader") < 0) ai = "oolite-traderAI.js";
		bounty = null;
	} 
	else if (pr.indexOf('escort') > -1) {
		if (js && nm.indexOf("Escort") < 0) ai = "oolite-escortAI.js";		
		if (g && g.leader && (g.leader.AIScript.name.indexOf("Assassin") > -1 || g.leader.AIScript.name.indexOf("Pirate") > -1)) {
			bounty = true;
		}
	} else if (pr.indexOf('freighter') > -1) {
		if (ai && nm.indexOf("Pirate Freighter") < 0) ai = "oolite-pirateFreighterAI.js";
		bounty = true;
	} else if (pr.indexOf('pirate') > -1 && pr.indexOf('fighter') > -1) {
		if (js && nm.indexOf("Pirate Fighter") < 0) ai = "oolite-pirateFighterAI.js";
		bounty = true;					
	} else if (pr.indexOf('pirate-interceptor') > -1 || pr.indexOf('aegis-raider') > -1) {
		if (js && nm.indexOf("Pirate") < 0) ai = "oolite-pirateInterceptorAI.js";
		bounty = true;
	} else if (pr.indexOf('pirate') > -1 || pr.indexOf('raider') > -1) {
		if (js && nm.indexOf("Pirate") < 0) ai = "oolite-pirateAI.js";
		bounty = true;
	}
	if (ai) {
		ship.setAI(ai);
		if (this._debug_AI) log("Assassin_shipset_pack", sc.name + " : set " + ai + " for " + s.displayName + " [" + k + "]");
	}
	if (bounty && !s.bounty) {
		var bonus = system.info.government + ~~(random() * system.info.techlevel);
		if (!g) {
			bonus += ~~(random() * 8);
		} else if (g && g.leader && g.leader.bounty) {
			bonus += ~~(random() * 0.25 * g.leader.bounty);
			bounty = false;			
		}
		ship.setBounty(20 + bonus,"setup actions");
	}
	
	// set hiddenBounty
	if (bounty && s.bounty) {
		if (this._debug_Bty) log("Assassin_shipset_pack", sc.name + " : add hiddenBounty for " + pr + ": " + s.displayName + " [" + k + "]");
		ship.script._hiddenBounty = s.bounty;
		ship.script._storedHiddenBounty = ship.script._hiddenBounty;
		bounty = null;
	} else if (this._debug_Bty) log("Assassin_shipset_pack", sc.name + " : no hiddenBounty for " + pr + ": " + s.displayName + " [" + k + "]");
	if (bounty === null) ship.bounty = 0;
}
this._setWeaponsToShip = function (ship,bias,debug) {
	var s = ship;
	var pr = s.primaryRole;
	var sc = s.script;
	var k = s.dataKey;
	var level;
	var dg = debug;
	if (!dg) dg = this._debug_Wpn; 
	//WIP: Default and new lasers
	if (this._weaponNoneSet[k]) {
		sc.$setWeapons = false;
		if (dg) log("Assassin_shipset_pack", sc.name + " :  setup lasers denied for " + s.displayName + " [" + k + "]");
	}
	var l = worldScripts["new_lasers"];
	if (!l && !ship.autoWeapons) {
		// Set default lasers // TODO: pirate[1.3]
		level = this.$setLevel(pr, bias);
		if (sc.$setWeapons) {
			if (dg) log("Assassin_shipset_pack", sc.name + " : pre-set(" + level.toFixed(1) + ") to default lasers for " + ship.name);
			this._setWeapons(s, level, dg)
		}
	} else if (l && !ship.autoWeapons) {
		// Set New lasers / Set Uber lasers // this script not set for escort, fighter and freighter roles // TODO: pirate[1.3]
		level = this.$setNewWeaponsLevel(pr, bias);
		if (sc.$setWeapons) {
			if (dg) log("Assassin_shipset_pack", sc.name + " : pre-set(" + level.toFixed(1) + ") to new lasers for " + ship.name);
			this._setNewLasers(s, level, dg)
		}
	}
	// Replacement to extra missiles
	if (this._extraMissiles.length > 0 && level > 2 && bias < 0.3) {
		this._setExtraMissiles(s, 1)
	}
}
/* Levels:
 * <= 1: FP
 *    2: FB
 *    3: FB, AB (rare in core)
 *    4: FM, AB (not used in core)
 *    5: FM, AM (not used in core)
 * >= 6: FM, [NONE, AB] (not used in default core-function)
 * Fractional levels may be one or other (e.g. 2.2 = 80% 2, 20% 3)
 * Side weapons unchanged
 */
/* Run _setWeapons on the default ship */
this._setWeapons = function (ship,level,logging,debug) { // copy from populator
	var s = ship;
	var pr = s.primaryRole;
	var sc = s.script;
	var k = s.dataKey;
	var lg = logging;
	var dg = debug;
	if (!lg) lg = this._debug_Wpn;
	if (!dg) dg = this.logging;
	level += this.$weaponLevelBias;
	if (s.autoWeapons) { // autoWeapons is inverted rule for _setWeapons!!!
		// default is not to change anything
		if (dg) log(this.name, "Check a shipdata and ship script condition! No change anything for [" + k + "](" + pr + ")");
		return false;
	}
	if (pr.indexOf('fighter') > -1 || pr.indexOf('escort') > -1) {
		// not will set for all escort and fighter roles
		if (dg) log(this.name, "Default lasers doesn't set to escort and fighter roles : [" + k + "](" + pr + ")");
		return false;
	}
	var fwent = ship;
	if (ship.forwardWeapon == null) {
		var se = ship.subEntities;
		for (var i = 0; i < se.length; i++) {
			if (se[i].forwardWeapon != null) {
				if (fwent != ship) {
					if (dg) log(this.name, "auto_weapons doesn't work on ships with MFLs : [" + k + "](" + pr + ")");
					return false; // auto_weapons doesn't work on ships with MFLs
				}
				fwent = se[i];
			}
		}
	}
	if (this._aftWeaponNone[ship.dataKey]) {
		ship.aftWeapon = null;
		if (lg) log(this.name, "aft laser doesn't set for [" + k + "](" + pr + ")");
		//return false; // off to set a forward uber laser
	}
	var choice = Math.floor(level);
	if (level - Math.floor(level) > Math.random()) {
		choice++;
	}
	if (choice <= 1) {
		fwent.forwardWeapon = "EQ_WEAPON_PULSE_LASER";
		ship.aftWeapon = null;
	} else if (choice == 2) {
		fwent.forwardWeapon = "EQ_WEAPON_BEAM_LASER";
		ship.aftWeapon = null;
	} else if (choice == 3) {
		fwent.forwardWeapon = "EQ_WEAPON_BEAM_LASER";
		if (!this._aftWeaponNone[ship.dataKey]) ship.aftWeapon = "EQ_WEAPON_BEAM_LASER";
	} else if (choice == 4) {
		fwent.forwardWeapon = "EQ_WEAPON_MILITARY_LASER";
		if (!this._aftWeaponNone[ship.dataKey]) ship.aftWeapon = "EQ_WEAPON_BEAM_LASER";
	} else if (choice == 5) {
		fwent.forwardWeapon = "EQ_WEAPON_MILITARY_LASER";
		if (!this._aftWeaponNone[ship.dataKey]) ship.aftWeapon = "EQ_WEAPON_MILITARY_LASER";
	} else if (choice >= 6) // not used in default core-function
	{
		fwent.forwardWeapon = "EQ_WEAPON_MILITARY_LASER";
		if (!this._aftWeaponNone[ship.dataKey]) {
			if (Math.random() > 0.60) {
				ship.aftWeapon = null;
			} else {
				ship.aftWeapon = "EQ_WEAPON_PULSE_LASER"
			}
		}
	}
	if (lg) log(this.name, "Set (l:" + level.toFixed(1) + " -> c:" + choice + ") " + fwent.forwardWeapon + "/" + ship.aftWeapon + " on the [" + k + "](" + pr + ")");
	return true;
}
/* Roles: this._setWeapons()
 *
 * - hunter : [1.5] / mixed weapons, medium[1.9] / usually ensure have beam lasers, heavy[2.2] / occasionally give aft lasers
 *
 * - pirate : [1.3], [1.75] / hasHyperspaceMotor, leader[2.8] / usually give aft laser
 *
 * - pirate-fighter : light[1.2] / basic fighters, medium[1.8] / often beam weapons, heavy[2.05] / very rarely aft lasers
 *
 * - pirate-aegis-raider has very heavily armed : [2.7]
 *
 * - pirate-interceptor has heavily armed 		: [2.3]
 *
 * - assassin 									: light[2], medium[2.5], heavy[2.8], extra[1.8]
 *
 * - smuggler has rarely good weapons 			: [1.2]
 *
 * - opportunist 								: [2.5]
 *
 */
/* Run _setEscortWeapons on the escort group */
this._setEscortWeapons = function (mothership) { // copy from populator
	if (!mothership.escortGroup) { // TEST: rustem: error in oolite-populator.js : [escortGroup --> group]?
		return;
	}
	var eg = mothership.escortGroup.ships; // TEST: rustem: error in oolite-populator.js : [escortGroup --> group]?
	for (var i = eg.length - 1; i >= 0; i--) {
		var ship = eg[i];
		if (ship == mothership) {
			continue;
		}
		if (ship.autoWeapons) // autoWeapons is inverted rule for _setEscortWeapons!!!
		{
			continue;
		}
		var pr = ship.primaryRole;
		if (pr == "escort" || pr == "pirate-light-fighter") {
			this._setWeapons(ship, 1.3); // usually lightly armed as escorts
		} else if (pr == "escort-medium" || pr == "pirate-medium-fighter") {
			this._setWeapons(ship, 1.8); // usually heavily armed as escorts
		} else if (pr == "escort-heavy" || pr == "pirate-heavy-fighter") {
			this._setWeapons(ship, 2.05); // rarely have an aft laser
		}
	}
}
/* Roles:
 *
 * - escort[1.3], medium[1.8], heavy[2.05]
 *
 * - _addFreighter, _addCourier, _addSmuggler : this._setEscortWeapons(t[0])
 *
 * - _addPiratePack : this._setEscortWeapons(lead[0])
 *
 */
/* Levels: New lasers: 1-5, Uber lasers: 6-10
 * <= 1: FP
 *    2: FB, AP (mass>175t)
 *    3: FB, AB
 *    4: FM, AB
 *    5: FM, AM
 * 	  6: FU, [NONE, AB, AM], AB (chance: 0.75)
 *    7: FU, [NONE, AB, AM]
 *    8: FU, [NONE, AB, AM]
 * >= 9: FU, [NONE, AB, AM]
 * For level 6 and more, if mass>175t, first setup: NONE --> AP (also a little chance for sniping)
 * Fractional levels may be one or other (e.g. 2.2 = 80% 2, 20% 3)
 * Side weapons unchanged
 */
/* Run _setNewLasers on the default ship (test) */
this._setNewLasers = function (ship,level,logging,debug) { // edit _setWeapons for New Lasers
	var s = ship;
	var pr = s.primaryRole;
	var sc = s.script;
	var k = s.dataKey;
	var lg = logging;
	var dg = debug;
	if (!lg) lg = this._debug_Wpn;
	if (!dg) dg = this.logging;
	level += this.$weaponLevelBias;
	if (s.autoWeapons) // autoWeapons is inverted rule for setNewLasers!!!
	{
		// default is not to change anything
		if (dg) log(this.name, "weapons was set by populator, so it is not to change anything for " + s.name + " (" + pr + ")");
		return false;
	}
	if (pr.indexOf('fighter') > -1 || pr.indexOf('escort') > -1) {
		// not will set for all escort and fighter roles
		if (dg) log(this.name, "New lasers doesn't set to escort and fighter roles: " + s.name + " (" + pr + ")");
		return false;
	}
	var fwent = ship;
	if (ship.forwardWeapon == null) {
		var se = ship.subEntities;
		for (var i = 0; i < se.length; i++) {
			if (se[i].forwardWeapon != null) {
				if (fwent != ship) {
					if (lg) log(this.name, "Setup of new lasers doesn't work on ships with MFLs for " + s.name + " (" + pr + ")");
					return false; // setNewLasers doesn't work on ships with MFLs
				}
				fwent = se[i];
			}
		}
	}
	var aftCheck = true;
	if (this._aftWeaponNone[ship.dataKey] || ship.aftWeapon === "WEAPON_NONE") {
		aftCheck = false;
		ship.aftWeapon = null;
		if (lg) log(this.name, "aft laser doesn't set on the [" + k + "](" + pr + ")");
		//return false; // off to set a forward uber laser
	}
	var choice = Math.floor(level);
	var chanceFrd = Math.random();
	var chanceAft = Math.random();
	if (level - Math.floor(level) > Math.random()) {
		choice++;
	}
	if (choice >= 6 && aftCheck) // forward uber laser, aft laser: NONE(mass>175t: --> AP), AB, AM
	{
		if (ship.awardEquipment("EQ_LASER_COUPLER")) {
			if (chanceAft > 0.4) {
				if (ship.mass > 175000) {
					if (chanceAft > 0.95) ship.aftWeapon = "EQ_WEAPON_HIRAD_LASER" // sniping					
					else if (chanceAft > 0.8) ship.aftWeapon = "EQ_WEAPON_EPULSE_LASER"
					else if (chanceAft > 0.6) ship.aftWeapon = "EQ_WEAPON_PULSE_LASER"
				} else ship.aftWeapon = null // "WEAPON_NONE"
			} else if (chanceAft > 0.25) {
				ship.aftWeapon = "EQ_WEAPON_BEAM_LASER";
			} else if (chanceAft > 0.15) {
				ship.aftWeapon = "EQ_WEAPON_EBEAM_LASER";
			} else {
				ship.aftWeapon = "EQ_WEAPON_MILITARY_LASER";
			}
		} else {
			log(this.name, "Uber lasers doesn't set (l:" + level + " -> c:" + choice + ") on the [" + k + "](" + pr + ")");
			return false;
		}
	}
	if (choice <= 1) { // Pulse Lasers(threat_assessment): EQ_WEAPON_EPULSE_LASER(0.0) + // Defence Lasers: EQ_WEAPON_BLAST_LASER(0.125) / EQ_WEAPON_DUAL_LASER(0.25)
		if (chanceFrd > 0.85) {
			fwent.forwardWeapon = "EQ_WEAPON_DUAL_LASER";
		} else if (chanceFrd > 0.50) {
			fwent.forwardWeapon = "EQ_WEAPON_BLAST_LASER";
		} else if (chanceFrd > 0.15) {
			fwent.forwardWeapon = "EQ_WEAPON_EPULSE_LASER"; // + cool-running
		} else {
			fwent.forwardWeapon = "EQ_WEAPON_PULSE_LASER";
		} // EQ_WEAPON_PULSE_LASER(0.0)
		ship.aftWeapon = null;
	} else if (choice == 2) { // VariScan Lasers(0.25): EQ_WEAPON_HVARISCAN_LASER / EQ_WEAPON_VARISCAN_LASER + // Beam Lasers: EQ_WEAPON_EBEAM_LASER(0.5)
		if (chanceFrd > 0.85) {
			fwent.forwardWeapon = "EQ_WEAPON_HVARISCAN_LASER";
		} else if (chanceFrd > 0.50) {
			fwent.forwardWeapon = "EQ_WEAPON_VARISCAN_LASER";
		} else if (chanceFrd > 0.15) {
			fwent.forwardWeapon = "EQ_WEAPON_EBEAM_LASER"; // + cool-running
		} else {
			fwent.forwardWeapon = "EQ_WEAPON_BEAM_LASER";
		} // EQ_WEAPON_BEAM_LASER(0.5)
		if (aftCheck && ship.mass > 175000 && ship.aftWeapon != "WEAPON_NONE") {
			if (chanceAft > 0.8) ship.aftWeapon = "EQ_WEAPON_PULSE_LASER"
			else if (chanceAft > 0.6) ship.aftWeapon = "EQ_WEAPON_EPULSE_LASER"
		} else ship.aftWeapon = null;
	} else if (choice == 3) { // Beam Lasers: EQ_WEAPON_EBEAM_LASER(0.5) + // Burst Lasers: EQ_WEAPON_BURST_LASER(0.75) / EQ_WEAPON_ASSAULT_LASER(1.0)
		if (chanceFrd > 0.85) {
			fwent.forwardWeapon = "EQ_WEAPON_ASSAULT_LASER"; // dogfighting
		} else if (chanceFrd > 0.50) {
			fwent.forwardWeapon = "EQ_WEAPON_BURST_LASER"; // dogfighting
		} else if (chanceFrd > 0.15) {
			fwent.forwardWeapon = "EQ_WEAPON_EBEAM_LASER"; // + cool-running
		} else {
			fwent.forwardWeapon = "EQ_WEAPON_BEAM_LASER";
		} // EQ_WEAPON_BEAM_LASER(0.5)
		if (aftCheck && chanceAft > 0.2) ship.aftWeapon = "EQ_WEAPON_BEAM_LASER"; // EQ_WEAPON_BEAM_LASER
	} else if (choice == 4) { // Bolt Lasers(0.75): EQ_WEAPON_HIRAD_LASER / EQ_WEAPON_STAR_LASER + // Burst Lasers: EQ_WEAPON_ASSAULT_LASER(1.0)
		if (chanceFrd > 0.85) {
			fwent.forwardWeapon = "EQ_WEAPON_HIRAD_LASER"; // sniping
		} else if (chanceFrd > 0.50) {
			fwent.forwardWeapon = "EQ_WEAPON_STAR_LASER"; // sniping
		} else if (chanceFrd > 0.15) {
			fwent.forwardWeapon = "EQ_WEAPON_ASSAULT_LASER"; // dogfighting
		} else {
			fwent.forwardWeapon = "EQ_WEAPON_MILITARY_LASER";
		} // EQ_WEAPON_MILITARY_LASER(1.0)
		if (aftCheck) {
			if (chanceAft < 0.16) ship.aftWeapon = "EQ_WEAPON_HIRAD_LASER"
				else ship.aftWeapon = "EQ_WEAPON_BEAM_LASER"
		} // EQ_WEAPON_BEAM_LASER
	} else if (choice == 5) { // Military Lasers(1.0): EQ_WEAPON_EMILITARY_LASER // versatile and powerful combat lasers
		if (chanceFrd > 0.3) {
			fwent.forwardWeapon = "EQ_WEAPON_EMILITARY_LASER"; // + cool-running
		} else {
			fwent.forwardWeapon = "EQ_WEAPON_MILITARY_LASER";
		} // EQ_WEAPON_MILITARY_LASER
		if (aftCheck) {
			if (chanceAft < 0.26) ship.aftWeapon = "EQ_WEAPON_HIRAD_LASER"
				else ship.aftWeapon = "EQ_WEAPON_MILITARY_LASER"
		} // EQ_WEAPON_MILITARY_LASER
	} else if (choice == 6) { // 'Uber' Lasers(0.5): EQ_WEAPON_FRONTIER_LASER(0.25) / EQ_WEAPON_WILLIAMS_LASER / EQ_WEAPON_ZEUSCORP_LASER / EQ_WEAPON_ANDERSON_LASER
		if (chanceFrd > 0.75) {
			fwent.forwardWeapon = "EQ_WEAPON_FRONTIER_LASER"; // standard pulse laser except that it kills things
		} // EQ_WEAPON_BEAM_LASER
		else if (chanceFrd > 0.50) {
			fwent.forwardWeapon = "EQ_WEAPON_WILLIAMS_LASER"; // powerful, medium speed defence laser
		} else if (chanceFrd > 0.25) {
			fwent.forwardWeapon = "EQ_WEAPON_ZEUSCORP_LASER"; // little beauty of a VariScan laser
		} else {
			fwent.forwardWeapon = "EQ_WEAPON_ANDERSON_LASER"; // mining
		}
		if (aftCheck && chanceAft < 0.16) {
			ship.aftWeapon = "EQ_WEAPON_BEAM_LASER"; // AM --> AB
		} // little NONE(mass>175t: AP), more AB, AM
	} else if (choice == 7) { // 'Uber' Lasers: EQ_WEAPON_LUCAS_LASER(0.75) / EQ_WEAPON_QVC_LASER(1.0)
		if (chanceFrd > 0.5) {
			fwent.forwardWeapon = "EQ_WEAPON_LUCAS_LASER"; // powerful beam laser
		} else {
			fwent.forwardWeapon = "EQ_WEAPON_QVC_LASER"; // amazing burst laser
		} // EQ_WEAPON_BEAM_LASER
		if (aftCheck && chanceAft < 0.16) {
			ship.aftWeapon = "EQ_WEAPON_EBEAM_LASER"; // AM --> cool-running AB
		}
		// Aft: first setup: NONE(mass>175t: AP), AB, AM
	} else if (choice == 8) { // 'Uber' Lasers(1.0): EQ_WEAPON_DEXM_LASER
		fwent.forwardWeapon = "EQ_WEAPON_DEXM_LASER"; // EQ_WEAPON_MILITARY_LASER // hard bolt laser
		// Aft: first setup: NONE(mass>175t: AP), AB, AM
	} else if (choice >= 9) { // 'Uber' Lasers(1.0): EQ_WEAPON_RIMMERACE_LASER
		fwent.forwardWeapon = "EQ_WEAPON_RIMMERACE_LASER"; // EQ_WEAPON_MILITARY_LASER // cool military laser
		if (aftCheck && chanceAft > 0.85) {
			ship.aftWeapon = "EQ_WEAPON_HIRAD_LASER"; // more sniping		
		}
		// Aft: first setup: NONE(mass>175t: AP), AB, AM
	}
	if (lg) log(this.name, "Set (l:" + level.toFixed(1) + " -> c:" + choice + ") " + fwent.forwardWeapon + "/" + ship.aftWeapon + " on the [" + k + "](" + pr + ")");
	return true;
}
/* Roles:
 *
 * - ships from tech assassin shipset pack : this._setNewLasers(t[0])
 *
 */
// Loads one type of the extra missile to ship (with equipmentKey replacement option)
this._setExtraMissiles = function (ship,extraMissileLauncher,equipmentKey) {
	var l = parseInt(extraMissileLauncher);
	var m, eqpKey, extra;
	var extras = [];
	var capacity = ship.missileCapacity;
	if (this._extraMissiles.length === 0) return;
	if (!equipmentKey) eqpKey = "EQ_MISSILE"
		else eqpKey = equipmentKey;
	extras = extras.concat(this._extraMissiles);
	if (l && l > 0 && ship.mass > 175000) { // >= Boa
		extras.push("EQ_NPC_CT_MINE")
	}
	extra = extras[Math.floor(Math.random() * extras.length)];
	
	// v1 - full load
	// m = capacity;
	// while (m--) {
	// 	ship.removeEquipment(eqpKey);
	// 	ship.awardEquipment(extra);
	// }
	// v2 - not work
	// for (var i = ship.missiles.length -1 ; i >= 0 ; i--) {
	// 	if (ship.missiles[i].primaryRole == eqpKey) {
	// 		ship.removeEquipment(eqpKey);
	// 		ship.awardEquipment(extra);
	// 	}
	// }
	// v3 - perhaps partial, depend from amount of missiles
	for (var i = ship.missiles.length -1 ; i >= 0 ; i--) {
		ship.removeEquipment(eqpKey);
		ship.awardEquipment(extra);
	}//if (capacity > 1 && ship.missiles.length === 0) ship.awardEquipment(extra);
	//log(this.name, extra + " extra missile will be installed."); // in case eqpKey = "EQ_HARDENED_MISSILE" not installed
}
/* Bias:
 * +N = N 50% chances that each normal missile converted to hardened
 * -N = N 50% chances that each normal missile removed
 */
this._setMissiles = function(ship,bias) // not used, for example
{
	if (ship.autoWeapons)
	{
		var chance = Math.pow(0.5,Math.abs(bias));
		for (var i = ship.missiles.length -1 ; i >= 0 ; i--)
		{
			if (ship.missiles[i].primaryRole == "EQ_MISSILE" && chance < Math.random())
			{
				ship.removeEquipment("EQ_MISSILE");
				if (bias > 0)
				{
					ship.awardEquipment("EQ_HARDENED_MISSILE");
				}
			}
		}
	}
}
this.$defaultRoles = [
	"trader", "trader-courier", "trader-smuggler",
	"pirate", "pirate-light-freighter", "pirate-medium-freighter", "pirate-heavy-freighter",
	"pirate-light-fighter", "pirate-medium-fighter", "pirate-heavy-fighter",
	"hunter", "hunter-medium", "hunter-heavy", "assassin-light", "assassin-medium", "assassin-heavy",
	"escort", "escort-light", "escort-medium", "escort-heavy",
	"stealth-assassin", "stealth-hunter", "stealth-raider", "stealth-courier", "stealth-assassin-light", "stealth-assassin-medium", "stealth-assassin-heavy"
]
this.$setRoleName = function (role) {
	// no roles: fighter, miner, police, scavenger, shuttle, wingman
	var pr, r = role;
	// single role
	if (r.indexOf('courier') > -1) {
		return "trader-courier";
	} else if (r.indexOf('smuggler') > -1) {
		return "trader-smuggler";
	} else if (r.indexOf('interceptor') > -1) {
		return "pirate-interceptor";
	} else if (r.indexOf('raider') > -1) {
		return "pirate-aegis-raider";
	}
	// 1 word
	if (r.indexOf('trader') > -1) {
		pr = "trader";
	} else if (r.indexOf('hunter') > -1) {
		pr = "hunter";
		if (r.indexOf('light') > -1) {
			return "hunter";
		}
	} else if (r.indexOf('escort') > -1) {
		pr = "escort";
	} else if (r.indexOf('assassin') > -1) {
		pr = "assassin";
	} else if (r.indexOf('pirate') > -1) {
		pr = "pirate";
		if (r.indexOf('heavy') > -1) {
			pr += "-heavy-freighter";
		} else if (r.indexOf('medium') > -1) {
			pr += "-medium-freighter";
		} else if (r.indexOf('light') > -1) {
			pr += "-light-freighter";
		}
		return pr;
	}
	// 2 word
	if (r.indexOf('heavy') > -1) {
		pr += "-heavy";
	} else if (r.indexOf('medium') > -1) {
		pr += "-medium";
	} else if (r.indexOf('light') > -1) {
		pr += "-light";
	}
	if (!pr) pr = r; // not found a standart roles and will set a role
	return pr;
}
this.$setLevel = function (role,bias) {
	var level;
	var pr = role;
	var level = 1;
	var addLevel = 1; // for default-ship role
	var chance = bias;
	// 1 word
	if (pr.indexOf('hunter') > -1) {
		level = 0.4
	} else if (pr.indexOf('pirate') > -1) {
		level = 0.7
	} else if (pr.indexOf('assassin') > -1) {
		level = 1.0
	}                                // hunter != assassin 
	// 2 word
	// base level: hunter: [1.5], medium[1.9], heavy[2.2+0.6], smuggler[1.2]
	// base level: assassin: light[2], medium[2.5], heavy[2.8+0.6], pirate-interceptor[2.3], pirate-aegis-raider[2.7]
	if (pr === "hunter") {
		level += 1.1
	} else if (pr.indexOf('light') > -1) {
		level += 1.0
	}                                // a: l(100) --> 0/65/35/0/0/0
	else if (pr.indexOf('interceptor') > -1) {
		level += 1.6
	} else if (pr.indexOf('medium') > -1) {
		level += 1.5
	} // a: m(100) --> 0/21/71/8/0/0
	else if (pr.indexOf('raider') > -1) {
		level += 2.0
	} else if (pr.indexOf('heavy') > -1) {
		level += 2.4;
		addLevel = 2.4;
	}                                // a: h(100) --> 0/0/18/50/24/8 : heavy roles is expandable: add 0.6 to base + 0.6 to level 6
	else if (pr.indexOf('smuggler') > -1) {
		level += 0.2
	} else if (pr.indexOf('shipset') > -1) {
		level += 0.4;
		addLevel = 4.4;
	}                                // for console demo test based on shipKey | shipset --> 8/36/24/14/12/6
	// unusual role
	else if (pr.indexOf('assassin') > -1 || pr.indexOf('hunter') > -1) {
		if (chance < 0.142) {
			level = 2.8;
			addLevel = 3.0;
		}                         // ~ 0.25 : heavy roles is expandable
		else if (chance < 0.428) {
			level = 2.5
		}                        // ~ 0.50
		else {
			level = 2
		}                        // ~ 1.00
	}
	level += Math.pow(Math.random(), 2) * addLevel; // ^2 : a: l/m/h(100) --> 0/27/41/20/9/3
	return level
}
this.$setNewWeaponsLevel = function (role,bias) {
	var level;
	var pr = role;
	var level = 1;
	var addLevel = 1; // for default-ship role
	var chance = bias;
	// 1 word
	if (pr.indexOf('hunter') > -1) {
		level = 0.7
	} else if (pr.indexOf('pirate') > -1) {
		level = 0.7
	} else if (pr.indexOf('assassin') > -1) {
		level = 1.0
	} // hunter != assassin
	// 2 word
	// level: hunter: [0.9], medium[1.9], heavy[3.4], smuggler[1.5]
	// level: assassin: light[1.2], medium[2.2], heavy[3.7], interceptor[2.0], raider[2.7]
	if (pr === "hunter") {
		level += 0.2;
	} else if (pr.indexOf('light') > -1) {
		level += 0.2;
	} else if (pr.indexOf('interceptor') > -1) {
		level += 1.3;
	} else if (pr.indexOf('medium') > -1) {
		level += 1.2;
		addLevel = 3;
	} else if (pr.indexOf('raider') > -1) {
		level += 2.0;
		addLevel = 4;
	} else if (pr.indexOf('heavy') > -1) {
		level += 2.7;
		addLevel = 6;
	} else if (pr.indexOf('smuggler') > -1) {
		level += 0.5
	} else if (pr.indexOf('shipset') > -1) {
		level += 3;
		addLevel = 6;
	} // for console demo test based on shipKey
	// unusual role
	else if (pr.indexOf('assassin') > -1 || pr.indexOf('hunter') > -1) {
		if (chance < 0.142) {
			level = 3.7;
			addLevel = 6;
		} // ~ 0.25
		else if (chance < 0.428) {
			level = 2.2;
			addLevel = 3;
		} // ~ 0.50
		else {
			level = 1.2
		} // ~ 1.00
	}
	level += Math.pow(Math.random(), 3) * addLevel; // ^3
	return level
}
this._setPrimaryRoleToShip = function (ship) {
	var pr = ship.primaryRole;
	if (pr) {
		var dr = this.$defaultRoles;
		if (dr.indexOf(pr) < 0) {
			ship.primaryRole = this.$setRoleName(pr); // log(this.name +" : set a primary role: "+ ship.primaryRole);
		}
		return ship.primaryRole;
	}
}
this._setStealthToShip = function (ship) {
	// add our shipExitedWormhole, shipDied and shipRemoved events to the ship
	// monkey patch if necessary
	var s = ship;
	var sc = s.script; // TODO?: s.scriptInfo.telescope
	if (!sc.$stealthMode) {
		sc.$stealthMode = this.$stealthMode;
		
		if (sc.shipEnergyBecameFull) sc.$stealth_ovr_shipEnergyBecameFull = sc.shipEnergyBecameFull;
		sc.shipEnergyBecameFull = this.$stealth_shipEnergyBecameFull;
		if (sc.shipEnergyIsLow) sc.$stealth_ovr_shipEnergyIsLow = sc.shipEnergyIsLow;
		sc.shipEnergyIsLow = this.$stealth_shipEnergyIsLow;
		
		s.scannerDisplayColor1 = [0, 0, 0, 0];
	}
}
this.$stealthMode = function (state) {
	if (state && state == "off") {
		this.ship.scannerDisplayColor1 = "yellowColor";
		this.ship.scannerDisplayColor2 = "redColor";
	} else {
		this.ship.scannerDisplayColor1 = [0, 0, 0, 0];
		this.ship.scannerDisplayColor2 = [0, 0, 0, 0];
	}
}
this.$stealth_shipEnergyBecameFull = function () {
	if (this.ship.script.$stealth_ovr_shipEnergyBecameFull) this.ship.script.$stealth_ovr_shipEnergyBecameFull(); //whom, why
	this.$stealthMode("on");
}
this.$stealth_shipEnergyIsLow = function () {
	if (this.ship.script.$stealth_ovr_shipEnergyIsLow) this.ship.script.$stealth_ovr_shipEnergyIsLow();
	this.$stealthMode("off");
}
/* Ship addition functions for BountySystem_MostWanted */
this._delayedAddMostWanted = function (ship,t) {
	// delay need for set dta.shipName and etc.
	var w = worldScripts.Assassin_shipset_pack;
	if (ship) {
		w._wantedGroup = ship; //ship; //_wantedGroup.push(ship); //w._leader = ship; //log(this.name, ship);
		if (!t) {
			t = 4;
		}
		if (!w.$addShipTimer) {
			w.$addShipTimer = new Timer(w, w._delayedAddMostWanted, t, t);
		} else {
			w.$addShipTimer.start();
		}
	} else {
		w.$addShipTimer.stop();
		w.$addShipToMostWanted(w._wantedGroup);
	}
}
this.$addShipToMostWanted = function (entity) { //copy a function this.$testData from GC MostWanted --> been modify for ASPack
	var mw = worldScripts.BountySystem_MostWanted;
	// v1 - for push version
	//if (entity && entity.count > 0) {
	// v2 - basic
	if (entity) {
		var ship;
		/*// v1
		for (var i=0; i<entity.length;i++) {
			if (this._leader != entity[i]) {
				log(this.name, "Replaced wanted pilot");
			}
		}
		ship = this._leader; //*/
		// v2
		ship = entity; // ship // group.ships[0] //if (this.logging) log(this.name, ship);
		var group = ship.group;
		if (this._debug) log(this.name, "Start setting the group: " + this._groupName);
		/*// set up a dummy type 3
		var syslist = system.info.systemsInRange(7);
		var list = [];
		for (var i = 0; i < syslist.length; i++) {
			list.push(syslist[i].systemID);
		}
		this._safeDangerous.push({
			id: system.ID,
			dangerous: list
		});
		//*/
		// TODO: select optimal version, need modify for ASPack or read a ship.homeSystem?
		// create a record
		var s_name, a_type, s_type = 4;
		var role = ship.primaryRole;
		if (!role) { // TEST: Fixed in future
			log(this.name, "Error: not create a record, this ship: " + ship + " from group: " + group.name + " have incorrect role setting");
			return
		}
		if (role.indexOf('assassin') > -1) {
			a_type = 3;
			s_type = 8; // temp for ASPack
			if (role.indexOf('heavy') > -1) {
				s_type = 9
			}
		}
		// default start setting for ASPack
		var dta = {};
		dta.index = mw.$newItemIndex();
		dta.routeMode = "OPTIMIZED_FOR_JUMPS";
		dta.pending = true; // TEST: in order to not create repeatly
		dta.bounty = 0;
		/* // setting from GC MostWanted, version = "0.5"
			- assassin:
					// bounty between 250 and 11600
					dta.realBounty = parseInt(Math.random() * 100 + 250) + ((parseInt(Math.random() * 250) + 200) * Math.pow(5, s_type - 7));
					// vary rarely add some really juicy numbers
					if (Math.random() > 0.97) dta.realBounty += parseInt(Math.random() * 5000 + 5000);
					dta.routeMode = "OPTIMIZED_FOR_TIME";
			- $testData:
					// bounty between 250 and 15200
					dta.realBounty = parseInt(Math.random() * 100 + 250) + ((parseInt(Math.random() * 250) + 200) * Math.pow(3, s_type - 4));
					dta.bounty = 60 + (Math.floor(Math.random() * 8)) + Math.floor(Math.random() * 8);
					dta.pending = false;
		*/
		// WIP: set to ASPack
		if (Math.random() > 0.5) dta.routeMode = "OPTIMIZED_FOR_TIME";
		// bounty between 250 and 11600 // WIP: + ship.script.$initBounty ?
		dta.realBounty = parseInt(Math.random() * 100 + 250) + ((parseInt(Math.random() * 250) + 200) * Math.pow(5, s_type - 7));
		// vary rarely add some really juicy numbers
		if (Math.random() > 0.97) dta.realBounty += parseInt(Math.random() * 5000 + 5000);
		// build a ship
		var def_role = "assassin-light"; // set for ASPack	 //var role = "";
		switch (s_type) {
			case 4:
				//role = "pirate"; // dta.shipAI = "oolite-pirateAI.js";
				dta.escortsRole = "pirate";
				break;
			case 5:
				//role = "pirate-light-freighter";
				dta.escortsRole = "pirate-light-fighter";
				break;
			case 6:
				//role = "pirate-medium-freighter";
				dta.escortsRole = "pirate-medium-fighter";
				break;
			case 7:
				//role = "pirate-heavy-freighter";
				dta.escortsRole = "pirate-heavy-fighter";
				break;
			case 8:
				//role = "assassin-medium"; // dta.shipAI = "oolite-assassinAI.js";
				dta.escortsRole = "assassin-light";
				break;
			case 9:
				//role = "assassin-heavy"; // dta.shipAI = "oolite-assassinAI.js";
				dta.escortsRole = "assassin-medium";
				break;
		}
		if (mw.$roleExists(role) === false) role = def_role;
		dta.shipAI = "oolite-assassinAI.js"; // temp for ASPack
		//var found = false;
		//do {
		//dta.shipDataKey = mw.$getRandomShipKey(role);
		//var shipPlist = Ship.shipDataForKey(dta.shipDataKey);
		//dta.shipType = shipPlist.name;
		//// make sure this is a serious pirate (not a bug or hognose)
		//if (shipPlist.max_cargo >= 20 + (s_type - 4) * 20) found = true;
		//} while (found === false);
		// TODO: added to ASPack ? --> no for assassin: 2 below string
		dta.shipDataKey = ship.dataKey; // TODO: need added: "bounty_"+ shipKey ?
		s_name = ship.displayName.split(': ');
		dta.shipType = s_name[0]; // dta.shipType = ship.name;
		dta.shipName = s_name[1];
		dta.personality = ship.entityPersonality; // can only do this in Oolite 1.81 or greater --> dta.personality = Math.floor(Math.random() * 32767);
		dta.primaryRole = role;
		dta.accuracy = ship.accuracy;
		dta.heatInsulation = 2; // or ship.heatInsulation
		switch (s_type) {
			case 4:
				dta.equipment = "FORE:EQ_WEAPON_MILITARY_LASER";
				break;
			case 5:
				dta.equipment = "FORE:EQ_WEAPON_BEAM_LASER,AFT:EQ_WEAPON_BEAM_LASER,EQ_CLOAKING_DEVICE";
				break;
			case 6:
				dta.equipment = "FORE:EQ_WEAPON_MILITARY_LASER,AFT:EQ_WEAPON_BEAM_LASER,EQ_CLOAKING_DEVICE";
				break;
			case 7:
				dta.equipment = "FORE:EQ_WEAPON_MILITARY_LASER,AFT:EQ_WEAPON_MILITARY_LASER,EQ_CLOAKING_DEVICE";
				break;
			case 8:
			case 9:
				var aft = "null", frw = "null"; // TODO TEST
				if (ship.aftWeapon) aft = ship.aftWeapon.equipmentKey;				
				if (ship.forwardWeapon) frw = ship.forwardWeapon.equipmentKey;
				dta.equipment = "FORE:" + frw + ",AFT:" + aft;
				break;
		}
		// ship.hasEquipment("EQ_ESCAPE_POD") / ship.hasEquipment(EquipmentInfo.infoForKey("EQ_ESCAPE_POD"))
		if (ship.equipmentStatus("EQ_ESCAPE_POD") === "EQUIPMENT_OK") {
			dta.equipment += ",EQ_ESCAPE_POD";
		} else {
			dta.equipment += ",X:EQ_ESCAPE_POD";
		}
		if (ship.equipmentStatus("EQ_SHIELD_BOOSTER") === "EQUIPMENT_OK") { // ship.equipmentStatus() (replaces playerShip.equipmentStatus()) work in oolite v1.84
			dta.equipment += ",EQ_SHIELD_BOOSTER";
			dta.realBounty += parseInt(Math.random() * 1000 + 1000); // WAIT: Optimal ?
		}
		if (ship.equipmentStatus("EQ_SHIELD_ENHANCER") === "EQUIPMENT_OK") {
			dta.equipment += ",EQ_SHIELD_ENHANCER";
			dta.realBounty += parseInt(Math.random() * 2000 + 2000); // WAIT: Optimal ?
		}
		// booster and shield enhancer not fixed equipment, semi-variable usable due to ship script and shipdata.plist
		if (ship.equipmentStatus("EQ_CLOAKING_DEVICE") === "EQUIPMENT_OK") {
			dta.equipment += ",EQ_CLOAKING_DEVICE";
			dta.realBounty += parseInt(Math.random() * 3000 + 3000); // WAIT: Optimal ?
		} else {
			dta.equipment += ",X:EQ_CLOAKING_DEVICE";
		}
		// disable before solve about including in shipdata.plist
		//if (ship.equipmentStatus("EQ_MILITARY_JAMMER") === "EQUIPMENT_OK") {
		//dta.equipment += ",EQ_MILITARY_JAMMER";
		//dta.realBounty += parseInt(Math.random() * 2000 + 2000); // WAIT: Optimal ?
		//} else {
		//dta.equipment += ",X:EQ_MILITARY_JAMMER";
		//}
		if (ship.forwardWeapon.equipmentKey.indexOf('EQ_WEAPON_CANNON_SNIPER_GUN') > -1 ||
			ship.forwardWeapon.equipmentKey.indexOf('EQ_WEAPON_CANNON_HEAVY_SNIPER_GUN') > -1) {
			dta.realBounty += parseInt(Math.random() * 1500 + 1500); // WAIT: Optimal ? // log(this.name, "Added realBounty for forwardWeapon : "+ ship.forwardWeapon.equipmentKey);
		}
		if (ship.aftWeapon.equipmentKey.indexOf('EQ_WEAPON_CANNON_SNIPER_GUN') > -1 ||
			ship.aftWeapon.equipmentKey.indexOf('EQ_WEAPON_CANNON_HEAVY_SNIPER_GUN') > -1) {
			dta.realBounty += parseInt(Math.random() * 1500 + 1500); // WAIT: Optimal ? // log(this.name, "Added realBounty for aftWeapon : "+ ship.aftWeapon.equipmentKey);			
		}
		// WAIT: assassin can buy "X"-equipment in the route ?
		//dta.escorts = ((s_type - 3) * 2); // 2, 4, 6 or 8
		// adding escorts
		dta.escorts = 0;
		dta.escortData = [];
		/*//
		dta.escorts = 0;
		dta.escortData = [];
		//if (group && group.leader.entityPersonality === ship.entityPersonality) {
			// this ship is leader group
			this.$addEscortsToData(ship,dta);
		//}
		//*/
		// TEST: need modify for ASPack or read a ship.escorts?
		//mw.$addEscortsToData(dta);
		// create a pilot, picking a random system as home
		//t var pilot = mw.$createPilot(Math.floor(Math.random() * 256)); // TODO: added to ASPack or ship.crew[0]?
		var p = ship.crew[0];
		dta.pilotDescription = p.description;
		dta.pilotName = p.name;
		dta.pilotHomeSystem = p.homeSystem;
		dta.pilotSpecies = p.species;
		/* // setting : assassin - from GC MostWanted, version = "0.5"
					// where are they now, and where are they headed?
					// pick a safe/dangerous element, start them in the safe one
					dta.arrayIndex = Math.floor(Math.random() * this._safeDangerous.length);
					dta.movement = 3; // star-type movement (if there is more than 1 dangerous system against the safe one, otherwise same as a milkrun)
					var sd = this._safeDangerous[dta.arrayIndex];
					dta.system = sd.dangerous[0];
					dta.destinationSystem = sd.id;
					// when did they dock?
					dta.dockTime = clock.adjustedSeconds - (Math.random() * 21600 + 3600);
					// when will they leave dock?
					dta.departureTime = clock.adjustedSeconds + (Math.random() * 21600 + 3600);
					// arrival time in new system will be departureTime + travelTime(time between systems) + extraTime(random flight time)
					// is their current position visible to GalCop?
					dta.updateChance = (s_type / 15);
		*/
		// where are they now, and where are they headed?
		// pick a safe/dangerous element, start them in the safe one
		dta.arrayIndex = mw._safeDangerous.length; //  /- 1 / edit for ASPack
		dta.movement = 3; // star-type movement (if there is more than 1 dangerous system against the safe one, otherwise same as a milkrun)
		//var sd = this._safeDangerous[dta.arrayIndex]; // modify for ASPack
		var ss = this._safeSystemsForShipset(a_type);
		dta.system = system.ID; // this system : system.info.systemID;
		// v1 - default
		//dta.system = sd.id; //sd.dangerous[0];
		//dta.destinationSystem = sd.dangerous[0]; //sd.id;
		// v2 - from ship
		//dta.destinationSystem = ship.destinationSystem; //ship.homeSystem;
		// v3 - from script
		dta.destinationSystem = ss[Math.floor(Math.random() * ss.length)];
		// WAIT: need modify safe/dangerous element or createCustomPath for ASPack?
		// after leader add escort record
		this.$addEscortsToData(ship, dta);
		// when did they dock?
		dta.dockTime = clock.adjustedSeconds - 3600; // (3600 * 10.5);
		// when will they leave dock?
		dta.departureTime = clock.adjustedSeconds + (3600 * 4.5); //(3600 * 8.5);
		// arrival time in new system will be departureTime + travelTime(time between systems) + extraTime(random flight time)
		// is their current position visible to GalCop?
		dta.updateChance = (s_type / 15); // WIP: (s_type / 15) | ((s_type - 3) / 5)
		// WAIT: need modify dockTime, departureTime, updateChance for ASPack?
		if (Math.random() > dta.updateChance) { // 0 | dta.updateChance
			dta.lastVisibleSystem = dta.system;
			dta.lastVisibleDestination = dta.destinationSystem;
			dta.updated = dta.dockTime;
		} else {
			dta.lastVisibleSystem = -1;
		}
		dta.lastVisibleHistory = [2];
		//dta.lastVisibleHistory = {updated:dta.updated, system:dta.lastVisibleSystem, destination:dta.lastVisibleDestination};
		// WAIT: need modify current position visible for ASPack?
		/* // finalise settings - from GC MostWanted, version = "0.5"
			if (Math.random() > dta.updateChance) {
				dta.lastVisibleSystem = dta.system;
				dta.lastVisibleDestination = dta.destinationSystem;
				dta.updated = clock.adjustedSeconds - ((Math.random() * 14) * 86400) + (Math.random() * 86400);
			} else {
				dta.lastVisibleSystem = -1;
			}
			dta.lastVisibleHistory = [2];
		*/
		if (mw._debug) mw.$writeDataToLog(dta, "Creating special record");
		mw._wanted.push(dta);
		this._wanted_amount++;
		if (this._debug) log(this.name, "Added special record to MostWanted list")
	} else {
		log(this.name, "Error: d't added a ship to MostWanted list : " + ship);
		return
	}
	this._leader.length = 0; // this._wantedGroup = [];
	//*//
	// TEST: Need update ship or this.$updateMovementData() will right?
	this.$updateShip(ship, dta)
	//if (dta.escorts > 0 && dta.escortData.length > 0) {}
	if (this._sdc_Installed) {
		var sdc = worldScripts.StationDockControl;
		sdc.$awaitShipDocking({
			shipName: dta.shipName,
			pilotName: dta.pilotName,
			worldScript: this.name,
			callback: "$sdc_shipDockedWithStation",
			parameter: dta.index,
			launchCallback: "$bounty_launchCallback"
		});
	}
	/* temp before release
	if (mw._wanted.push(dta)) {
		if (mw._debug) mw.$writeDataToLog(dta, "Creating special record");
		if (this.logging) log(this.name, "Added special record to MostWanted list");
		return true
	} else {
		return false
	}
	*/
}
this.$addEscortsToData = function (leader,dta) {
	dta.escorts = 0;
	dta.escortData = [];
	if (!leader.group) { // TEST: rustem: error in oolite-populator.js : [escortGroup --> group]?
		return;
	}
	var eg = leader.group.ships; // TEST: rustem: error in oolite-populator.js : [escortGroup --> group]?
	if (this._debug) log(this.name, "Start setting : " + (eg.length - 1) + " escorts");
	for (var i = eg.length - 1; i >= 0; i--) {
		var escort = eg[i];
		if (escort == leader) {
			continue;
		}
		dta.escorts++;
		var esc = {};
		// small update
		var bounty = escort.bounty;
		var hiddenBounty = 0;
		var e_name = escort.displayName.split(': ');
		var personality = this._encodePersonality(escort);
		if (escort._hiddenBounty) {
			hiddenBounty = escort._hiddenBounty;
			escort.script._hiddenBounty = hiddenBounty;
			escort.script._storedHiddenBounty = hiddenBounty;
			if (this._debug) log(this.name, "Added hiddenBounty : " + hiddenBounty);
		}
		escort.shipUniqueName = e_name[1];
		escort.entityPersonality = personality;
		// create record
		esc["escortShipKey"] = escort.dataKey;
		esc["escortShipName"] = e_name[1];
		//esc["escortPersonality"] = escort.entityPersonality; // Math.floor(Math.random() * 32768);
		esc["escortPersonality"] = personality;
		esc["escortPilotName"] = escort.crew[0].name; // this.$generateName(); //randomName() +" "+ randomName();
		if (dta.primaryRole.indexOf("pirate") >= 0) {
			esc["escortBounty"] = bounty + Math.floor(Math.random() * (d.accuracy * 5) + 5);
		} else {
			esc["escortBounty"] = bounty;
		}
		esc["escortHiddenBounty"] = hiddenBounty + Math.floor(Math.random() * 30 + 5); // WAIT: Add bonus (sc._hiddenBounty) for asssasin band ?
		dta.escortData.push(esc);
		if (this._debug) log(this.name, "Added " + dta.escorts + " escort ship to MW leader");
	}
}
this.$updateShip = function (leader,dta) {
	var scn = worldScripts.BountySystem_WarrantScanner;
	var mw = worldScripts.BountySystem_MostWanted;
	// attach scripts for leader
	mw.$bounty_launchCallback("launched", leader);
	//dta.fuel = 7 - (rt ? rt.distance : 0);
	// need added goods for trader, pirate roles
	//dta.goods = "";
	// update ship : some comment
	scn.$setBounty(leader, dta.realBounty);
	leader.setBounty(dta.bounty, "setup actions");
	leader.shipUniqueName = dta.shipName;
	leader.homeSystem = dta.pilotHomeSystem;
	leader.destinationSystem = dta.destinationSystem;
	leader.fuel = 7; //ship.fuel = dta.fuel;
	leader.script._mostWanted = dta.index;
	if (this._debug) log(this.name, "Update leader in real-time");
	if (!leader.group) {
		return;
	}
	var count = 0;
	var eg = leader.group.ships;
	if (this._debug) log(this.name, "Start update : " + (eg.length - 1) + " escorts");
	for (var i = eg.length - 1; i >= 0; i--) {
		var escort = eg[i];
		if (escort == leader) {
			continue;
		}
		count++;
		// update escort
		//escort.shipUniqueName = escort.escortShipName; // been set in this.$addEscortsToData
		//escort.entityPersonality = escort.escortPersonality; // been set in this.$addEscortsToData
		escort.fuel = 7;
		escort.homeSystem = dta.pilotHomeSystem;
		escort.destinationSystem = leader.destinationSystem;
		// set the seed values so that the pilot's species can be defined by their home system
		var seed = "0 0 0 0 " + dta.pilotHomeSystem.toString() + " 2";
		escort.setCrew({
			name: escort.escortPilotName,
			origin: dta.pilotHomeSystem,
			bounty: escort.escortBounty,
			random_seed: seed
		});
		mw.$bounty_escortLaunchCallback("launched", escort);
		escort.script._mostWanted = dta.index;
		//escort.script._hiddenBounty = item.escortHiddenBounty; // been set in this.$addEscortsToData
		//wpop._setWeapons(esc, 2.5); // not need for ASPack
		// temp disable
		//escort.group = grp;
		//grp.addShip(escort);
		// try to do an escort offer
		//escort.performEscort();
	}
	if (this._debug) log(this.name, "Updated " + count + " escorts in real-time");
}
// functions for encode and decode a personality
this._encodePersonality = function (ship) {
	//ship = this.ship;
	var p = 0; // personality: [0..32767]
	var code;
	if (ship.forwardWeapon) {
		code = this.$itemEncode[ship.forwardWeapon.equipmentKey];
		p |= code << 10;
	}
	if (ship.aftWeapon) {
		code = this.$itemEncode[ship.aftWeapon.equipmentKey];
		p |= code << 5;
	}
	if (ship.equipmentStatus("EQ_ESCAPE_POD") === "EQUIPMENT_OK") {
		p |= 0x0010;
	}
	if (ship.equipmentStatus("EQ_SHIELD_BOOSTER") === "EQUIPMENT_OK") {
		p |= 0x0008;
	}
	if (ship.equipmentStatus("EQ_SHIELD_ENHANCER") === "EQUIPMENT_OK") {
		p |= 0x0004;
	}
	// booster and shield enhancer not fixed equipment, semi-variable usable due to ship script and shipdata.plist
	if (ship.equipmentStatus("EQ_CLOAKING_DEVICE") === "EQUIPMENT_OK") {
		p |= 0x0002;
	}
	if (ship.equipmentStatus("EQ_MILITARY_JAMMER") === "EQUIPMENT_OK") {
		p |= 0x0001;
	}
	if (this._debug_Eqp) log(this.name, ship.script.name + " : escort has personality: " + p);
	/*/ tepmlate
	if (ship.portWeapon) {
		code = this.$itemEncode[ship.portWeapon.equipmentKey];
		p |= code<<20;
	}
	if (ship.starboardWeapon) {
		code = this.$itemEncode[ship.starboardWeapon.equipmentKey];
		p |= code<<15;
	}
	//*/
	return p;
}
this._decodePersonality = function (personality) {
	// ship = this.ship; // var personality = ship.entityPersonality
	var eq = new Object; // equipments
	var code = (personality & 0x7C00) >> 10;
	eq.frw = this.$itemDecode(code);
	if (!eq.frw) {
		eq.frw = null;
	}
	code = (personality & 0x03E0) >> 5;
	eq.aft = this.$itemDecode(code);
	if (!eq.aft) {
		eq.aft = null;
	}
	code = (personality & 0x0010) >> 4;
	if (code) {
		eq.ep = "EQ_ESCAPE_POD";
	}
	code = (personality & 0x0008) >> 3;
	if (code) {
		eq.sb = "EQ_SHIELD_BOOSTER";
	}
	code = (personality & 0x0004) >> 2;
	if (code) {
		eq.se = "EQ_SHIELD_ENHANCER";
	}
	code = (personality & 0x0002) >> 1;
	if (code) {
		eq.cd = "EQ_CLOAKING_DEVICE";
	}
	code = (personality & 0x0001);
	if (code) {
		eq.mj = "EQ_MILITARY_JAMMER";
	}
	return eq;
}
this.$itemEncode = { // for encode	// 5 bits for 31 lasers + none state
	"WEAPON_NONE": 0x0,
	"EQ_WEAPON_PULSE_LASER": 0x1,        // 1
	"EQ_WEAPON_EPULSE_LASER": 0x2,
	"EQ_WEAPON_BLAST_LASER": 0x3,
	"EQ_WEAPON_DUAL_LASER": 0x4,
	"EQ_WEAPON_VARISCAN_LASER": 0x5,
	"EQ_WEAPON_HVARISCAN_LASER": 0x6,    // 6, free code: 7, 8
	"EQ_WEAPON_BEAM_LASER": 0x9,
	"EQ_WEAPON_EBEAM_LASER": 0xA,
	"EQ_WEAPON_BURST_LASER": 0xB,
	"EQ_WEAPON_ASSAULT_LASER": 0xC,      // 12
	"EQ_WEAPON_MILITARY_LASER": 0x11,    // 17
	"EQ_WEAPON_HIRAD_LASER": 0x12,
	"EQ_WEAPON_STAR_LASER": 0x13,
	"EQ_WEAPON_EMILITARY_LASER": 0x14,   // 20, free code: 21, 22
	"EQ_WEAPON_WILLIAMS_LASER": 0xD,     // 13
	"EQ_WEAPON_ZEUSCORP_LASER": 0xE,     // 14, free code: 15, 16
	"EQ_WEAPON_LUCAS_LASER": 0x17,       // 23
	"EQ_WEAPON_QVC_LASER": 0x18,
	"EQ_WEAPON_DEXM_LASER": 0x19,
	"EQ_WEAPON_RIMMERACE_LASER": 0x20    // 26, free code: 27..31
}
this.$itemDecode = function (code) {
	var eqpKey;
	// switch
	if (code === 0x0) {
		eqpKey === "WEAPON_NONE";
	}
	// pulse
	else if (code === 0x1) {
		eqpKey = "EQ_WEAPON_PULSE_LASER";
	} // 1
	else if (code === 0x2) {
		eqpKey = "EQ_WEAPON_EPULSE_LASER";
	} else if (code === 0x3) {
		eqpKey = "EQ_WEAPON_BLAST_LASER";
	} else if (code === 0x4) {
		eqpKey = "EQ_WEAPON_DUAL_LASER";
	} else if (code === 0x5) {
		eqpKey = "EQ_WEAPON_VARISCAN_LASER";
	} else if (code === 0x6) {
		eqpKey = "EQ_WEAPON_HVARISCAN_LASER";
	} // 6, free code: 7, 8
	// beam
	else if (code === 0x9) {
		eqpKey = "EQ_WEAPON_BEAM_LASER";
	} else if (code === 0xA) {
		eqpKey = "EQ_WEAPON_EBEAM_LASER";
	} else if (code === 0xB) {
		eqpKey = "EQ_WEAPON_BURST_LASER";
	} else if (code === 0xC) {
		eqpKey = "EQ_WEAPON_ASSAULT_LASER";
	} // 12
	// sniper
	else if (code === 0x11) {
		eqpKey = "EQ_WEAPON_MILITARY_LASER";
	} // 17
	else if (code === 0x12) {
		eqpKey = "EQ_WEAPON_HIRAD_LASER";
	} else if (code === 0x13) {
		eqpKey = "EQ_WEAPON_STAR_LASER";
	} else if (code === 0x14) {
		eqpKey = "EQ_WEAPON_EMILITARY_LASER";
	} // 20, free code: 21, 22
	// uber beam
	else if (code === 0xD) {
		eqpKey = "EQ_WEAPON_WILLIAMS_LASER";
	} // 13
	else if (code === 0xE) {
		eqpKey = "EQ_WEAPON_ZEUSCORP_LASER";
	} // 14, free code: 15, 16
	// uber sniper
	else if (code === 0x17) {
		eqpKey = "EQ_WEAPON_MILITARY_LASER";
	} // 23
	else if (code === 0x18) {
		eqpKey = "EQ_WEAPON_HIRAD_LASER";
	} else if (code === 0x19) {
		eqpKey = "EQ_WEAPON_STAR_LASER";
	} else if (code === 0x20) {
		eqpKey = "EQ_WEAPON_EMILITARY_LASER";
	} // 26, free code: 27..31
	// 5 bits for 31 lasers + none state
	/*/
	// escape pod
	if (eqpKey === "X:EQ_ESCAPE_POD") { code = 0x0; }
	else if (eqpKey === "EQ_ESCAPE_POD") { code = 0x1; }
	// energy
	if (eqpKey === "X:EQ_SHIELD_BOOSTER") { code = 0x0; }
	else if (eqpKey === "EQ_SHIELD_BOOSTER") { code = 0x1; }
	if (eqpKey === "X:EQ_SHIELD_ENHANCER") { code = 0x0; }
	else if (eqpKey === "EQ_SHIELD_ENHANCER") { code = 0x1; }
	if (eqpKey === "X:EQ_CLOAKING_DEVICE") { code = 0x0; }
	else if (eqpKey === "EQ_CLOAKING_DEVICE") { code = 0x1; }
	if (eqpKey === "X:EQ_MILITARY_JAMMER") { code = 0x0; }
	else if (eqpKey === "EQ_MILITARY_JAMMER") { code = 0x1; }
	// 4 bits for 4 equipment
	//*/
	return eqpKey;
}
// award equipment for GC MW escorts
this._awardWeaponEquipments = function (ship) {
	//ship = this.ship;
	if (ship) {
		var eq = this._decodePersonality(ship.entityPersonality); // ship.entityPersonality | entityPersonality
		if (eq) {
			if (this._debug_Eqp) log(this.name, ship.script.name + " : escort has lasers: frw:" + eq.frw + ", aft:" + eq.aft);
			ship.forwardWeapon = eq.frw;
			ship.aftWeapon = eq.aft;
			if (eq.ep) {
				ship.awardEquipment(eq.ep);
			}
			if (eq.sb) {
				ship.awardEquipment(eq.sb);
			}
			if (eq.se) {
				ship.awardEquipment(eq.se);
			}
			if (eq.cd) {
				ship.awardEquipment(eq.cd);
			}
			if (eq.mj) {
				ship.awardEquipment(eq.mj);
			}
			//} else {
			//if (eq != "") {
			//ship.awardEquipment(itm);
			//}
			//}
		}
	}
}
this._awardEquipment = function (shipData) { // not used
	ship = this.ship;
	if (shipData.equipment != "") {
		// process all the equipment additions
		var items = shipData.equipment.split(",");
		for (var j = 0; j < items.length; j++) {
			var itm = items[j];
			if (itm.indexOf(":") >= 0) {
				var subitems = itm.split(":");
				switch (subitems[0]) {
					case "X":
						ship.removeEquipment(subitems[1]);
						break;
					case "FORE":
						ship.forwardWeapon = subitems[1];
						break;
					case "AFT":
						ship.aftWeapon = subitems[1];
						break;
					case "PORT":
						ship.portWeapon = subitems[1];
						break;
					case "STARBOARD":
						ship.starboardWeapon = subitems[1];
						break;
				}
			} else {
				if (itm != "") {
					ship.awardEquipment(itm);
				}
			}
		}
	}
}
// award equipment for all types
this._setEquipments = function (ship,bias) {
	var s = ship;
	var pr = s.primaryRole;
	var sc = s.script;
	var k = s.dataKey;
	var chance = bias;
	// WIP: Check autoWeapons rules
	if (!s.autoWeapons && pr.indexOf('raider') > -1) { // raiders need the best equipment
		s.awardEquipment("EQ_FUEL_INJECTION");
		s.awardEquipment("EQ_SHIELD_BOOSTER");
		s.awardEquipment("EQ_ECM");
		s.fuel = 7;
		if (this._debug_Eqp) log("Assassin_shipset_pack", sc.name + " : award raider the best equipment: " + s.displayName + " [" + k + "]");
	}
	// WIP: Also for GC MostWanted added a little chance to shipdata vars.
	if (player.score > 512) {
		if (chance < 0.28) {
			s.awardEquipment("EQ_SHIELD_BOOSTER");
		}
		if (chance < 0.19) {
			s.awardEquipment("EQ_SHIELD_ENHANCER");
		}
		// heavy ship + not scanning by warrant scanner
		//if (chance < 0.12 && Math.random() < 0.7) { s.awardEquipment("EQ_MILITARY_JAMMER"); }
		if (chance < 0.08 && Math.random() < 0.7) {
			s.awardEquipment("EQ_CLOAKING_DEVICE");
		}
	}
	/* // not used
	// Install heat shields and injector
	if (this.ship.heatInsulation === 1) this.ship.heatInsulation = 2;
	if (this.ship.injectorSpeedFactor < 7) this.ship.injectorSpeedFactor = 7;
	//if (player.score >  512 && chance < 0.2) { this.ship.awardEquipment("EQ_SHIELD_BOOSTER"); }
	//if (player.score > 1024 && chance < 0.2) { this.ship.awardEquipment("EQ_SHIELD_ENHANCER"); }
	//if (player.score > 2560 && chance < 0.2) { this.ship.awardEquipment("EQ_MILITARY_JAMMER"); } // seen has_military_jammer in shipdata.plist
	//if (Math.random() < parseFloat(this.ship.scriptInfo.jammerChance)) // Chance of award jammer.
	//{
		//this.ship.awardEquipment("EQ_MILITARY_JAMMER")
	//}
	*/
}
// calculates an array of safe systems for assassin with close by dangerous systems
// For default GC MW: 		combination count : [88,0,0,0,0,0,0,0]
// For ASPack(assassin):	combination count : [88,0,0,0,0,0,0,0]
this._safeSystemsForShipset = function (type,range) {
	this._safeSystem.length = 0;
	var syslist;
	if (!range) range = 7;
	syslist = system.info.systemsInRange(range);
	var list = [];
	for (var i = 0; i < syslist.length; i++) {
		var sys = syslist[i];
		if (!sys.sun_gone_nova) {
			if (type === 1 && sys.government === 0 && sys.government < 5 ||
				type === 2 && sys.government === 1 && sys.government < 5 ||
				type === 3 && sys.government >= 2 && sys.government < 5) {
				list.push(sys.systemID);
			}
		}
	}
	if (list.length > 0) {
		if (this._debug) log(this.name, "Near safe systems(" + range + ") for type " + type + ": " + list);
	}
	return list;
}
this._calculateSafeDangerousSystemsForShipset = function (type) { // TEST: not used
	this._safeDangerous.length = 0;
	if (this._debug) log(this.name, "SafeDangerous systems for shipset: " + type);
	for (var i = 0; i < 256; i++) {
		var data = {
			id: i,
			dangerous: []
		};
		var sys = System.infoForSystem(galaxyNumber, i);
		// is this one of our safe systems (gov >= 5)
		if (!sys.sun_gone_nova) {
			if (type === 1 && sys.government === 0 && sys.government < 5 ||
				type === 2 && sys.government === 1 && sys.government < 5 ||
				type === 3 && sys.government >= 2 && sys.government < 5) {
				var locals = sys.systemsInRange(7);
				// any dangerous systems in range?
				for (var j = 0; j < locals.length; j++) {
					var lcl = locals[j];
					if (!lcl.sun_gone_nova && lcl.government <= 2) {
						data.dangerous.push(lcl.systemID);
					}
				}
			}
			if (data.dangerous.length > 0) {
				this._safeDangerous.push(data);
				if (this._debug) log(this.name, "SafeDangerous " + data.id + ", " + data.dangerous);
			}
		}
	}
}
this._delayedCheckPendingList = function (count,t) { // TEST: a wait for constant use
	// delay need for correctly allow a spawn ship.
	var w = worldScripts.Assassin_shipset_pack;
	if (count) {
		w.$num = count; // formal, not required for $checkPendingList
		if (!t) {
			t = 2;
		}
		if (!w.$checkPendingTimer) {
			w.$checkPendingTimer = new Timer(w, w._delayedCheckPendingList, t, t);
		} else {
			w.$checkPendingTimer.start();
		}
	} else {
		w.$checkPendingTimer.stop();
		w.$checkPendingList(w.$num); // (w.$num) | ()
		w.$num = 0;
	}
}
this.$checkPendingList = function (count) { // TEST: a wait for constant use
	var cond, mw = worldScripts.BountySystem_MostWanted;
	this._mw_escorts = false;
	if (mw._pending.length > 0) {
		for (var i = 0; i < mw._pending.length; i++) {
			var k = mw._pending[i].shipKey;
			if (k.indexOf('_AP_shipset') > -1) cond = true;
		}
		if (!cond && this._mw_count != 0) { // count | this._mw_count
			this._mw_count = 0;
			log(this.name, "!!! Protected from an error var: this._mw_count[" + count + "], count is set: 0");
		}
	}
}
 | 
                
                    | Scripts/ship_assassin_tech_shipset.js | "use strict";
this.name 			= "asp-tech-shipset";
this.author 		= "Rustem";
this.copyright 		= "2017";
this.description	= "Ship script for stealth ship from higher tech-level worlds";
this.licence     	= "CC BY-NC-SA 4.0";
this.version 		= "0.7.6";
// !!! : this script not will set some var for escort, fighter and freighter roles
// Addition to GC MostWanted list delevoped for assassin role. Current GC MostWanted v0.5.
// TODO: How do a clearing bounty for hunter (AIScript) in the thargoid-counter / friendly fire
this.logging = false;       // false/true
this.debug_AI = false;     // logging setAI
this.debug_Bty = false;    // logging setBounty
this.debug_Wpn = false;    // logging setWeapon
this.debug_Eqp = false;    // logging setEquipment
this.$setWeapons = true; // true - a tunning of the weapons. Also it is setted from worldscript blacklist.
// If New lasers OXP is not installed, then attempted setup default laser(P,B,M), otherwise get a heavy-weapon assassin in the gameplay (seen shipdata.plist).
this.shipSpawned = function (shipKey) {
	var s = this.ship;
	var k = s.dataKey;
	var pr = s.primaryRole;
	var sc = s.script;
	var w = worldScripts.Assassin_shipset_pack;
	if (k.indexOf("stealth") > -1) {
		w._setStealthToShip(s)
		if (this.logging) log("Assassin_shipset_pack", this.name + " : set a stealth features");
	}
	// WIP: Deny rule : for BountySystem_MostWanted
	var mostWanted = true;
	var mw = worldScripts.BountySystem_MostWanted;
	if (w && mw) {
		var index = sc._mostWanted; // leader & escorts
		if (index) {
			// allow spawn escort - version 2, other version locate in spawnArmouryAssassins
			//w._mw_escorts = true; log("assassin_shipset_pack", "! allow spawn mw-escorts"); // allow after leader
			s.bounty = 0; // if (s.primaryRole.indexOf("pirate") < 0) s.bounty = 0;
			// escort has non-default role name
			if (pr.indexOf(k) > -1) { // special set for escort
				if (s.group && s.group.leader && s.group.leader.AIScript.name.indexOf("Oolite Assassin") > -1) {
					s.switchAI("oolite-assassinAI.js");
					if (this.logging) log("Assassin_shipset_pack", this.name + " : set assassinAI for escort");
				}
				s.setBounty(s.bounty, "setup actions");
				w._awardWeaponEquipments(s)
			}
			// delete logging after testing
			if (this.logging) log("Assassin_shipset_pack", this.name + " - Amount: " + w._wanted_amount + ", spawn count: " + w._mw_count + ". This " + pr + "[" + k + "] has MW index: " + index + " --> deny a standart set AI, bounty, weapons");
			w._delayedCheckPendingList(w._mw_count); // TEST: a wait for constant use
			w._mw_count--;
			delete this.shipSpawned;
			return;
		}
		if (w._mw_count > 0) { // bountyVersionExists(k) // other solution: check ship.script._mostWanted ~ wanted.index
			// delete logging after testing
			if (this.logging) log("Assassin_shipset_pack", this.name + " - Amount: " + w._wanted_amount + ", spawn count: " + w._mw_count + ". This " + pr + "[" + k + "] in the MW pending list --> deny a standart set AI, bounty, weapons");
			w._delayedCheckPendingList(w._mw_count); // TEST: a wait for constant use
			w._mw_count--;
			delete this.shipSpawned;
			return;
		} else mostWanted = false;
	}
	// WIP: Calculate chance and set a chance for group leader.
	var chance = Math.random();
	var mw_chance = 0.7; // TODO: add secondary rule : for example, check _wanted.length < max_limit, distance to player
	var lead = s;
	var wg_name = "one_pilot";
	var g = s.group;
	if (g) {
		if (g.leader) lead = g.leader;
		if (g.leader && s.entityPersonality === g.leader.entityPersonality) {
			chance *= 0.428;
			mw_chance += 0.27;
		}
		if (!g.name) {
			wg_name = "wanted_pack_group_" + w._wanted_amount;
		} else {
			wg_name = g.name + " " + w._wanted_amount;
		}
	}
	// Setting a primaryRole, bounty, AI, weapons
	if (w) {
		// Check at array of default roles
		pr = w._setPrimaryRoleToShip(s);
		//mw_chance = 1; // always added to GC MW list for test
		// Check current bounty for role and set a hiddenBounty
		if (pr && !sc.hasOwnProperty("_hiddenBounty")) {
			if (this.debug_Bty) log(this.name + " : " + pr);
			// Check bounty and AI for primaryRole based on the oolite-populator rules // TODO: check ship.autoAI
			w._setBountyToShip(s);
		}
		// Set lasers and extra missiles
		if ($setWeapons) {
			w._setWeaponsToShip(s, chance, this.debug_Wpn);
		} else log("Assassin_shipset_pack", this.name + " : Check var: autoWeapons, $setWeapons, roles to set lasers for " + ship.name + "!!!");
		// Setting a equipments : award with chance 
		// all roles: shield booster, shield enhancer, military jammer and cloaking device
		// raiders role need the best equipment: fuel injection, ecm, shield booster
		w._setEquipments(s, chance);
	}
	// TEMP: Cut the role name : temp for beta-testing. Role identification will deleted before final release.
	if (s.displayName.indexOf('(') > -1 && s.displayName.indexOf(')') > -1) { // displayName | name
		var name = s.displayName.split(' ('); // var sname = name[1].split(': ');
		s.displayName = name[0]; //+": "+sname[1];
	}
	// WIP: Checking rule for addition this ship to GC MostWanted list : only assassin
	if (!mostWanted && (pr.indexOf('assassin') > -1)) { // WAIT: may be in next version will expanded roles
		// TEST: need modify secondary rule // !mw.$bountyVersionExists(k)
		if (w._wanted_amount < 5) {
			if (this.logging) log("Assassin_shipset_pack", this.name + " : " + mw_chance + " chance " + s.name + " add to MostWanted list");
			if (Math.random() < mw_chance) {
				if (s === lead) { // WAIT REPEAT OF ERROR: not lead will added to MostWanted list?
					var wg_name;
					w._leader = lead;
					w._groupName = wg_name;
					//if (this.logging)
					log("Assassin_shipset_pack", this.name + " : adding " + s.name + " [" + wg_name + "] to MostWanted list, count: " + w._wanted_amount);
					// creates new records of ship and pilot data
					w._delayedAddMostWanted(s);
				} else log("Assassin_shipset_pack", this.name + " : this ship is not leader for addition in MW list for pack: " + s);
			}
		} else log("Assassin_shipset_pack", this.name + " : Overlimited an amount ship in MW list for pack");
	}
	delete this.shipSpawned;
}
this.shipLaunchedEscapePod = function (escapepod, passengers) {
	if (this.$stealthMode) this.$stealthMode("off"); //test
	if (escapepod) {
		var pod = escapepod; // var ws = worldScripts.BountySystem_Core;
		// add for pirate only
		if (this._hiddenBounty) {
			this.$assassinEscapePod = true;
			// edit the pilot legalStatus // ALTERNATIVE: may be solved via oolite-character
			var pilotBounty = pod.crew[0].legalStatus + this._hiddenBounty;
			// set the seed values so that the pilot's species can be defined by their home system
			// var seed = "0 0 0 0 "+ pod.crew[0].homeSystem.toString() +" 2"; // WAIT: ?
			var seed = "0 0 0 0 0 0";
			pod.setCrew({
				name: pod.crew[0].name,
				origin: pod.crew[0].homeSystem,
				insurance: pod.crew[0].insuranceCredits,
				bounty: pilotBounty,
				short_description: pod.crew[0].description,
				random_seed: seed
			});
			// , random_seed:seed / , species:pod.crew[0].species
			this._hiddenBounty = null;
			if (this.debug_Bty) log("Assassin_shipset_pack", this.name + " : added the hiddenBounty to crew legalStatus of the pod");
		}
		//if (this.ship.bounty) this.ship.bounty = null; // WAIT: Need or edited this.shipDied? The oolite-core don't processed.		
		if (this.logging) {
			log("Assassin_shipset_pack", this.name + " : derelicted(orig) " + this.ship.name + " (" + this.ship.primaryRole + "), " + this.ship.displayName + " [" + this.ship.dataKey + "]");
			log("Assassin_shipset_pack", this.name + " : personality " + this.ship.entityPersonality + " apply ePod: " + pod.name + ", passengers: " + passengers);
		}
	}
}
this.shipDied = function (whom, cause) // copy and merge from main script deep_stealth_raiders
{
	// check bounty 	// 500 /1500 /4500 from shipdata stealth_...AP_shipset
	// If pod.crew[0].legalStatus will writen status then should fixed checking bounty mechanic.
	var bounty;
	if (this.$assassinEscapePod || this.ship.bounty && this._hiddenBounty) { // this.ship.bounty && this.$initBounty ... && !this.ship.isDerelict
		bounty = this._hiddenBounty;
		if (whom && whom.isPlayer && !player.ship.isCloaked) {
			player.credits += bounty;
			// TODO: Add delay consoleMessage
			player.consoleMessage("Bonus: " + formatCredits(bounty, true, true), 8);
			player.consoleMessage("Total: " + formatCredits(player.credits, true, true), 10);
			if (this.debug_Bty) log("Assassin_shipset_pack", this.name + " : " + bounty + " Cr. of the hiddenBounty added to player credits");
		}
	} else if (this.debug_Bty) log("Assassin_shipset_pack", this.name + " : bounty: " + this.ship.bounty + ", hiddenBounty: " + this._hiddenBounty);
	if (this.logging) {
		log("Assassin_shipset_pack", this.name + " : died(orig) " + this.ship.name + " (" + this.ship.primaryRole + "), " + this.ship.displayName + " [" + this.ship.dataKey + "]");
		log("Assassin_shipset_pack", this.name + " : personality " + this.ship.entityPersonality + " was killed by " + whom + " because of " + cause);
	}
	delete this.shipDied;
}
 |