| Config/script.js | "use strict";
this.name = "System Redux";
this.author = "spara, redspear";
this.copyright = "spara, redspear 2014";
this.description = "Add a planet/moon combinations to each system. Derived from System Redux code by Kaks, CaptKev and Svengali";
this.licence = "CC-BY-SA 3.0";
this.version = "0.10";
//pools for textures
this.$planetPool = new Array();
this.$moonPool = new Array();
this.$giantPool = new Array();
this.planet_mult = 5;
this.moon_mult = 2.5;
this.libSettings = {
	Name: this.name,
	Display: expandMissionText("srbase_config_display"), 
	Alias: expandMissionText("srbase_config_alias"), 
	Alive: "libSettings", 
	Notify: "oxpcNotifyOnChange",
	SInt: {
		S0: { Name: "max_moons", Def: 1, Min: 0, Max: 3, Desc: expandMissionText("srbase_max_moons") },
		S1: { Name: "max_planets", Def: 2, Min: 0, Max: 4, Desc: expandMissionText("srbase_max_planets") },
		S2: { Name: "moon_mult", Def: 2.5, Min: 2.5, Max: 8.0, Float: true, Desc: expandMissionText("srbase_moon_mult") },
		S3: { Name: "planet_mult", Def: 5, Min: 5.0, Max: 15.0, Float: true, Desc: expandMissionText("srbase_planet_mult") },
		Info: expandMissionText("srbase_config_sint_info")
	},
	EInt: {
		E0: { Name: "exSys", Def: 0, Min: 0, Max: 7, Desc: expandMissionText("srbase_exclude_sys").split("|") },
		Info: expandMissionText("srbase_config_eint_info")
	},
};
//public function to add planet textures to the pool
//call with array of texture names
this.addPlanetsToPool = function (planets) {
	if (planets) {
		for (var i = 0; i < planets.length; i++) {
			if (this.$planetPool.indexOf(planets[i]) === -1)
				this.$planetPool.push(planets[i]);
		}
	}
}
//public function to add moon textures to the pool
//call with array of texture names
this.addMoonsToPool = function (moons) {
	if (moons) {
		for (var i = 0; i < moons.length; i++) {
			if (this.$moonPool.indexOf(moons[i]) === -1)
				this.$moonPool.push(moons[i]);
		}
	}
}
//public function to add giant textures to the pool
//call with array of texture names
this.addGiantsToPool = function (giants) {
	if (giants) {
		for (var i = 0; i < giants.length; i++) {
			if (this.$giantPool.indexOf(giants[i]) === -1)
				this.$giantPool.push(giants[i]);
		}
	}
}
//public function to exclude specific systems
//call with an array of length 8 consisting of arrays of systems to exclude per galaxy
this.changeSystems = function (ar) {
	if (ar) {
		//i galaxy, ar[i][j] system
		for (var i = 0; i < ar.length; i++) {
			for (var j = 0; j < ar[i].length; j++) {
				if (this.excl[i].indexOf(ar[i][j]) === -1)
					this.excl[i].push(ar[i][j]);
			}
		}
	}
}
// public function to exclude a single system
// call with galaxy number and system ID
this.changeSystem = function (galID, sysID) {
	if (galID >= 0 && galID <= 7) {
		if (sysID >= 0 && sysID <= 255) {
			if (this.excl[galID].indexOf(sysID) === -1) this.excl[galID].push(sysID);
		}
	}
}
//oxp config
this.oxpcSettings = {
	Info: {
		Name: expandMissionText("srbase_config_alias"), EarlyCall: true, EarlySet: true, Notify: true,
		InfoE: expandMissionText("srbase_oxpc_info")
	},
	SInt0: { Name: "max_moons", Def: 0x3, Max: 0x3, Desc: expandMissionText("srbase_max_moons") },
	SInt1: { Name: "max_planets", Def: 0x4, Max: 0x4, Desc: expandMissionText("srbase_max_planets") },
	EInt0: { Name: "exSys", Def: 0x0, Max: 0x7, Desc: expandMissionText("srbase_exclude_sys").split("|") }
};
this.oxpcNotifyOnChange = function (n) {
	var idx = this.excl[0].indexOf(7);
	if ((this.exSys & 1)) {
		if (idx == -1) this.excl[0].push(7); //Lave
	} else {
		if (idx >= 0) this.excl[0].splice(idx, 1);
	}
	idx = this.excl[0].indexOf(147);
	if ((this.exSys & 2)) {
		if (idx == -1) this.excl[0].push(147); //Diso
	} else {
		if (idx >= 0) this.excl[0].splice(idx, 1);
	}
	idx = this.excl[0].indexOf(246);
	if ((this.exSys & 4)) {
		if (idx == -1) this.excl[0].push(246); //Tianve
	} else {
		if (idx >= 0) this.excl[0].splice(idx, 1);
	}
	return;
}
this.startUp = function () {
	//4 moons are currently defined in the planetdata.
	this.max_moons = 3;//max number of moons around a planet. There's no limit here.
	this.max_planets = 4;//maximum number of extra planets per system. extra planets might have moon. There's no limit here.
	this.extraPlanetMoonsProbability = 0.1;//the probability for an extra planet to have moons.
	this.exSys = 0;//for oxp config
	this.excl = [[], [], [], [], [], [], [], []];//excluded systems
	this.systemDone = false;//flag so that system gets populated only once
	this.runOnce = true;//controls the sorting of the pools
	if (missionVariables.SystemRedux_MaxMoons) this.max_moons = parseInt(missionVariables.SystemRedux_MaxMoons);
	if (missionVariables.SystemRedux_MaxPlanets) this.max_planets = parseInt(missionVariables.SystemRedux_MaxPlanets);
	if (missionVariables.SystemRedux_PlanetDistMult) this.planet_mult = parseFloat(missionVariables.SystemRedux_PlanetDistMult);
	if (missionVariables.SystemRedux_MoonDistMult) this.moon_mult = parseFloat(missionVariables.SystemRedux_MoonDistMult);
	if (missionVariables.SystemRedux_Exclude) this.exSys = JSON.parse(missionVariables.SystemRedux_Exclude);
}
this.startUpComplete = function () {
	// register our settings, if Lib_Config is present
	if (worldScripts.Lib_Config) worldScripts.Lib_Config._registerSet(this.libSettings);
}
this.playerWillSaveGame = function () {
	missionVariables.SystemRedux_MaxMoons = this.max_moons;
	missionVariables.SystemRedux_MaxPlanets = this.max_planets;
	missionVariables.SystemRedux_PlanetDistMult = this.planet_mult;
	missionVariables.SystemRedux_MoonDistMult = this.moon_mult;
	missionVariables.SystemRedux_Exclude = JSON.stringify(this.exSys);
}
this.systemWillPopulate = function () {
	//sort the pools on first launch so that the textures stay consistently regardless of the load order of the texture packs
	if (this.runOnce) {
		this.$planetPool.sort();
		this.$moonPool.sort();
		this.runOnce = false;
	}
	if (this.excl[galaxyNumber].indexOf(system.ID) === -1) {
		//init station array in sfap oxp
		if (worldScripts["stations_for_extra_planets"])
			worldScripts["stations_for_extra_planets"].initStationArray();
		this.$addPlanets();
	}
}
//the actual planet populator
this.$addPlanets = function () {
	//temporary arrays to be used with splice so that no two planet/moons/giant get the same texture in one system
	var tempPlanets = new Array();
	tempPlanets = tempPlanets.concat(this.$planetPool);
	var tempMoons = new Array();
	tempMoons = tempMoons.concat(this.$moonPool);
	var tempGiants = new Array();
	tempGiants = tempGiants.concat(this.$giantPool);
	var usedTextures = new Array();
	//inner functions need this
	var max_moon = this.max_moons;
	//function to manage textures so that if the same texture is used as moon and planet, it won't get shown twice in the same system
	function getTexture(pool, seed) {
		while (true) {
			if (pool.length !== 0) {
				var texNum = Math.floor(system.scrambledPseudoRandomNumber(seed) * pool.length);
				var texture = pool.splice(texNum, 1)[0];
				if (usedTextures.indexOf(texture) === -1) {
					usedTextures.push(texture);
					return texture;
				}
			}
			else return null;
		}
	}
	//function to add moons around given planet
	function addMoons(planet_position, planet_radius, seed) {
		//number of moon sizes defined in planetinfo.plist
		var moonSizes = 4;
		//number of moons to be added. extremes have probability weight of 0.5, others 1.
		var numberOfMoons = Math.round(system.scrambledPseudoRandomNumber(seed) * max_moons);
		//orbits. lowest is 2.5 * planet radius. station is usually at 2 * planet radius.
		var moonOrbits = new Array();
		for (var i = 0; i < max_moons; i++) moonOrbits.push(i);
		var baseMoonOrbit = planet_radius * worldScripts["System Redux"].moon_mult;
		var moonOrbitDifference = 30000;
		//for cinematic reasons moons are positioned so that when you view the main planet from wp, you should be able to see all the moons around it.
		//wp-planet line is kept empty.
		for (var i = 0; i < numberOfMoons; i++) {
			//texture
			var moonTexture = getTexture(tempMoons, system.scrambledPseudoRandomNumber(2 * (seed + i)));
			if (moonTexture === null) return;//if we're out of textures, abort.
			//body
			var moonBody = "ap-moon" + Math.floor(system.scrambledPseudoRandomNumber(3 * (seed + i)) * moonSizes);
			//position
			var moonOrbit = moonOrbits.splice(Math.floor(system.scrambledPseudoRandomNumber(11 * (seed + i)) * moonOrbits.length), 1)[0];
			var polar = Math.acos(1.4 * system.scrambledPseudoRandomNumber(5 * (seed + i)) - 0.7);
			var azimuth = 2.0 * Math.PI * system.scrambledPseudoRandomNumber(7 * (seed + i));
			var directionV = Vector3D(Math.sin(polar) * Math.cos(azimuth), Math.sin(polar) * Math.sin(azimuth), Math.cos(polar));
			var distance = baseMoonOrbit + moonOrbitDifference * moonOrbit;
			var moonPosition = planet_position.toCoordinateSystem("pwm").add(directionV.multiply(distance)).fromCoordinateSystem("pwm");
			setPopulatorMoon(moonTexture, moonBody, moonPosition);
		}
	}
	function setPopulatorPlanet(texture, body, coords, giant, radius) {
		system.setPopulator("ap_planet" + texture, {
			callback: function (pos) {
				var addedPlanet = system.addPlanet(body);
				addedPlanet.texture = texture;
				if (giant) {
					//for planetfall
					addedPlanet.solarGasGiant = true;
					//for gas giant skimmer
					addedPlanet.isGasGiant = true;
				}
				addedPlanet.position = pos;
			}.bind(this),
			location: "COORDINATES",
			coordinates: coords,
			priority: 100
		});
		//add station to planets with atmosphere
		if (worldScripts["stations_for_extra_planets"] && !giant)
			worldScripts["stations_for_extra_planets"].setStationPopulator(coords, radius);
	}
	function setPopulatorMoon(texture, body, coords) {
		system.setPopulator("ap_moon" + texture, {
			callback: function (pos) {
				var addedMoon = system.addMoon(body);
				addedMoon.texture = texture;
				addedMoon.position = pos;
			}.bind(this),
			location: "COORDINATES",
			coordinates: coords,
			priority: 101
		});
	}
	//all extra planets are positioned on incrementing distances calculated from the main planet. baseOrbit is the distance of the closest possible planet and orbitDifference is the increment from there on. These are multiples of unit calculated from wp-planet distance, so they differ from system to system. unit range is ~ 300 km - 400 km. For reference wp-planet range is ~ 300 km - 900 km.
	var orbits = new Array();
	for (var i = 0; i < this.max_planets; i++) orbits.push(i);
	var baseUnit = 1.0 / 6.0 * system.mainPlanet.position.magnitude() + 250000;
	var baseOrbit = this.planet_mult * baseUnit;//I would not go under 5. With 4, it's possible that an added planet is as close to the wp buoy as the main planet.
	var orbitDifference = 2.5 * baseUnit;
	//the number of extra planets in system. using Math.round gives smaller probabilities to the extremes, 0 and this.max_planets. With max planets 4, you'll be seeing more 1-3 extra planet systems than 0 or 4 extra planet systems. Probabitity weights are 0.5, 1, 1, 1, 0.5.
	var planetsInSystem = Math.round(system.pseudoRandomNumber * this.max_planets);
	for (var i = 0; i < planetsInSystem; i++) {
		//orbit.
		var orbit = orbits.splice(Math.floor(system.scrambledPseudoRandomNumber(galaxyNumber + 7 * (i + 1)) * orbits.length), 1)[0];
		//planet size. there are 9+1 different sizes defined in planetinfo.plist. 10th is reserved for gas giants that can only appear on outer orbits.
		var planetSizes = 9;
		if (orbit > 1 && tempGiants.length > 0) planetSizes = 10;
		var planetInd = Math.floor(system.scrambledPseudoRandomNumber(galaxyNumber + 2 * (i + 1)) * planetSizes);
		//texture
		if (planetInd === 9)
			var planetTexture = getTexture(tempGiants, system.scrambledPseudoRandomNumber(galaxyNumber + 11 * (i + 1)));
		else
			var planetTexture = getTexture(tempPlanets, system.scrambledPseudoRandomNumber(galaxyNumber + 11 * (i + 1)));
		if (planetTexture === null) continue; //if we're out of textures, skip to the next iteration.
		//body
		var planetBody = "ap-planet" + planetInd;
		if (planetInd === 9) var giant = true;
		else var giant = false;
		//position. planet is placed on a zone of a sphere around the main planet opposite to the sun.
		var polar = Math.acos(1.4 * system.scrambledPseudoRandomNumber(galaxyNumber + 5 * (i + 1)) - 1);
		var azimuth = 2.0 * Math.PI * system.scrambledPseudoRandomNumber(galaxyNumber + 3 * (i + 1));
		var directionV = Vector3D(Math.sin(polar) * Math.cos(azimuth), Math.sin(polar) * Math.sin(azimuth), Math.cos(polar));
		var distance = baseOrbit + orbitDifference * orbit;
		var planetPosition = directionV.multiply(distance).fromCoordinateSystem("psm");
		var radiuses = [5000, 5250, 5500, 5750, 6000, 6250, 6500, 6750, 7000, 20000];
		setPopulatorPlanet(planetTexture, planetBody, planetPosition, giant, radiuses[planetInd] * 10);
		//moons for extra planets
		if (system.scrambledPseudoRandomNumber(galaxyNumber + 17 * (i + 1)) < this.extraPlanetMoonsProbability) {
			//positioning depends on planet radius. Moon populator is set before the planet is added. Hence radiuses are given here.
			addMoons(planetPosition, radiuses[planetInd] * 10, galaxyNumber + 13);
		}
	}
	addMoons(system.mainPlanet.position, system.mainPlanet.radius, galaxyNumber + 19);
}
 |