And once again I was mistaken in that almost everything is alright...
As it turned out, everything worked due to the fact that the movement in orbits essentially did not work. Luckily, this is a relatively easy fix, but for now, you need to tweak the orbits script in Planet Orbits. Here is the tweaked code, I indicated the places where I made changes:
Code: Select all
"use strict";
this.name = "PlanetOrbits";
this.author = "Stranger";
this.description = "Adds planets on concentric orbits around the sun."
this.version = "1.8";
this.copyright = "This work is hereby placed in the public domain.";
/*
This script tightly based on Ebi, Kaks Orbits 1.2.1 script.
Original planet seeding procedure is overrided.
Moon filter radius increased to 2500 km.
Local year duration is a function of sun spectral class (reference to Sun Gear AstroLibrary included).
Periods of outer planets readjusted (0.5x multiplier added).
Original code reformatted to ease readings (yet too complicated to me!).
*/
function pow(x, y)
{
return Math.exp(y * Math.log(x));
}
// Maximum number of planets to be added (See planetinfo.plist as well).
this.MaxPlanets = 8;
// Outer planet orbits scale factor
this.$scaleOrbits = 0.5; // No works yet. Edit number in line 360 directly to have effect.
// Default scale value was 1.0.
// Days per year of the Main planet
this.Yr = 360;
// Get weights by linearily interpolating the planet radii as defined
// by [X0,Y0] and [X1,Y1]. Those weights are used as multiplier when
// calculating orbital periods. If X0 or X1 are 0 or undefined "orbits"
// will select the minimum or maximum from the planets in the
// system.planets list.
this.X0 = 2500 * 10; // planetinfo.plist minimum in game units
this.X1 = 18000 * 10; // planetinfo.plist maximum in game units
this.Y0 = pow(2, 3.0 / 4.0); // Compensate Keplers law and take square root
this.Y1 = pow(3.5, 3.0 / 4.0); // Thus, scale radius by values in [2,3.5]
// System spread factor
this.SpreadFactor = 3.0;
// Add a random offset in the range [0, t*RandomOffsetFactor] to the
// orbital period t of a planet.
this.RandomOffsetFactor = 0.1;
// Log to logfile (1) and/or console (2)
this.Verbose = 0; //1|4;
// Oh man, it's too tricky to get the OXP initialization order right
// for Oolite. It may be random, therefore I offer the farsun
// functionality here as well. Shifts the sun and increases (or
// decreases if less than 1) its distance to the main planet by this
// factor. Thus, the value 1 will not show any effect.
this.FarsunMultiplier = 1; // 6;
this.Log = function(dest, msg)
{
if (dest & 1)
log (msg);
if (dest & 2)
player.commsMessage(msg);
}
this.startUp = this.reset = function()
{
this.systemDone = false;
this.Log(this.Verbose & 1, "Initialising OXP " + this.name);
}
this.shipWillLaunchFromStation = function()
{
if (!this.systemDone)
{
this.shipWillExitWitchspace();
delete this.shipWillLaunchFromStation;
}
}
this.shipLaunchedFromStation = function()
{
if (!this.systemDone)
this.shipExitedWitchspace();
}
this.shipWillExitWitchspace = function()
{
if (system.isInterstellarSpace) return;
var w = worldScripts.AstroLibrary;
var sunRadius = system.sun.radius;
var sunMass = w.$astroLib_sunMass(sunRadius);
var mainYr = w.$astroLib_solPeriod(sunMass);
this.Yr = mainYr;
this.createOrbits();
}
this.shipExitedWitchspace = function()
{
if (system.isInterstellarSpace) return;
this.systemDone = true;
if ((this.Verbose & (2|4)) == 0 || this.innerPlanets == 0)
return;
var msg =
system.name + ": " +
this.innerPlanets + "+" +
this.outerPlanets + " planets";
if (this.info != undefined)
msg = msg + "[" + this.info + "]";
this.Log(2, msg);
}
this.isMoon = function(p)
{
// 10 * Radius from planetinfo.plist
return !p.isMainPlanet && p.radius < 2500 * 10;
}
this.mkPlanetIndex = function mkPlanetIndex()
{
function aPlanet(entity)
{
return entity.isPlanet
}
return system.filteredEntities(this, aPlanet, system.sun);
}
this.planetsMinMax = function(x)
{
var needX0 = this.X0 == undefined || this.X0 == 0;
var needX1 = this.X1 == undefined || this.X1 == 0;
var np = system.planets.length;
var x0 = +Infinity, x1 = 0;
if (needX0 || needX1)
{
for (var i = 0; i < system.planets.length; ++i)
{
if (this.isMoon(system.planets[i]))
{
np--;
continue;
}
if (system.planets[i].radius > x1)
x1 = system.planets[i].radius;
if (system.planets[i].radius < x0)
x0 = system.planets[i].radius;
}
}
x[0] = needX0 ? x0 : this.X0;
x[1] = needX1 ? x1 : this.X1;
return np;
}
this.addPlanets = function(id)
{
// Add planets in system dependent order. Id is used here in two
// ways:
// - Its lower bits determine the planets in planetinfo.plist
// - It represents a permutation and hence the order how the selected
// planets are added (see wikipedia for factoradic) and Entity-IDs
// are assigned.
var selectPlanet1 = system.scrambledPseudoRandomNumber(163);
var selectPlanet2 = system.scrambledPseudoRandomNumber(171);
var selectPlanet3 = system.scrambledPseudoRandomNumber(179);
var selectPlanet4 = system.scrambledPseudoRandomNumber(187);
var selectPlanet5 = system.scrambledPseudoRandomNumber(195);
var selectPlanet6 = system.scrambledPseudoRandomNumber(203);
var selectPlanet7 = system.scrambledPseudoRandomNumber(211);
var selectPlanet8 = system.scrambledPseudoRandomNumber(219);
var selectPlanetData = [
selectPlanet1,
selectPlanet2,
selectPlanet3,
selectPlanet4,
selectPlanet5,
selectPlanet6,
selectPlanet7,
selectPlanet8
];
var v = new Array(this.MaxPlanets), w = new Array(this.MaxPlanets);
// Avoid huge factorials by grouping up to 12 planets.
var mask = id;
for (var i = 0; i < this.MaxPlanets && mask != 0 && id != 0; )
{
var m = 0, f = 1;
// Type conversion prohibits use of the shift operator. Kind
// of weird to apply "&" on a floating point number!
for (; m < 12 && i < this.MaxPlanets; ++i, mask = Math.floor(mask / 2))
if ((mask & 1) != 0)
v[m] = i, w[m] = m, f *= ++m;
var fn = id % f; // fn = sum(j in [0..m-1]:j!*c[j]), c[j] <= j
id = Math.floor(id / f);
for (; m > 0; --m)
{
f /= m;
var c = Math.floor(fn / f);
fn -= f * c;
this.Log(this.Verbose,
"" + m + ":selecting oplanet" +
(v[w[c]] + 1) + "," + w[c] + "," +
c + "," + f + "," + fn);
var addPlanetTagIn = v[w[c]];
var addPlanetTagOut = 10*(addPlanetTagIn + 1) + Math.floor(selectPlanetData[addPlanetTagIn]*10);
system.addPlanet("oplanet" + addPlanetTagOut);
// system.addPlanet("oplanet" + (v[w[c]] + 1));
for (; c + 1 < m; ++c)
w[c] = w[c + 1];
}
}
}
this.createOrbits = function()
{
this.outerPlanets = 0;
this.innerPlanets = 0;
var s = system.sun;
// Is there system.witchpoint?
//var w = system.shipsWithPrimaryRole("buoy-witchpoint")[0]; // <-- tweaked: witchpoint always in (0, 0, 0)
var pm = system.mainPlanet;
//if (!s || !w || !pm) return; // <-- tweaked: variable w is removed
if (!s || !pm) return;
s.position=(pm.position.add(
s.position.subtract(pm.position).multiply(this.FarsunMultiplier)));
function PlanetVecs(s, w, p)
{
// "this" for sizzies:(
this.s = s;
this.sp = p.subtract(s);
this.dist = this.sp.magnitude();
// Rotation axis, perpendicular to the plane of triangle [s,p,w]
this.rx = this.sp.cross(w.subtract(s)).direction();
this.q = new Quaternion (1,0,0,0);
this.rotateQ = function(q, axis, angle)
{
// Ahruman's replacement for buggy Quaternion.rotate()
angle *= 0.5;
axis = axis.multiply(Math.sin(angle));
return q.multiply([Math.cos(angle), axis.x, axis.y, axis.z]);
}
this.position = function(a, d)
{
// Move sun to origin, rotate planet, and translate back again
return this.s.add(this.sp.rotateBy(
this.rotateQ(this.q, this.rx, a)).multiply(d));
}
}
var pv = new PlanetVecs(s.position, /* w.position */ new Vector3D(), pm.position); // <-- tweaked: witchpoint always in (0, 0, 0)
function SystemId(name)
{
this.prime = 29;
this.name = name;
this.code = 0;
this.charToInt = function(c)
{
var l = "abcdefghijklmnopqrstuvwxyz";
var i = l.indexOf(c);
if (i >= 0)
return i;
var u = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
i = u.indexOf(c);
return i >= 0 ? i : 0;
}
this.nextPrime = function()
{
var p = this.prime;
if ((p & 1) == 0)
++p;
for (;;)
{
p += 2;
for (var i = 3; ; i += 2)
{
if (i * i > p)
return this.prime = p;
if (p % i == 0)
break;
}
}
}
this.calcCode = function()
{
// Use letters of n as digits of number with base prime.
var l = this.name.length;
var x = 0;
var pp = 1;
for (var i = 0; i < l; ++i)
{
x += this.charToInt (this.name.charAt(i)) * pp;
pp *= this.prime;
}
return this.code = x;
}
}
// Derive numbers from system name
var id = new SystemId(system.name);
id.calcCode();
this.Log (this.Verbose, system.name + ":id is " + id.code);
this.addPlanets(id.code);
this.innerPlanets = 1;
var x = [+Infinity, 0];
var np = this.planetsMinMax(x);
if (np <= 1)
return;
function Map(x0, y0, x1, y1)
{
var m, X0 = x0, Y0 = y0;
if (x0 == x1 || y0 == y1)
{
m = (y0 + y1) / 2;
this.interpolate = function(x) { return m; }
}
else
{
m = (y1 - y0) / (x1 - x0);
this.interpolate = function(x) { return Y0 + m * (x - X0); }
}
}
var map = new Map(x[0], this.Y0, x[1], this.Y1);
function PlanetWeights(p, s)
{
this.c = 0, this.p = p, this.s = s;
this.product = function() { return this.s * this.c * this.p; }
this.next = function() { this.p = this.c; }
}
var ow = new PlanetWeights(
map.interpolate(pm.radius),
pow(this.SpreadFactor, 1.0 / (np - 1)));
var iw = new PlanetWeights(ow.p, ow.s);
function InnerOrbitalPeriod(orbits, s)
{
this.t = orbits.Yr;
var r = orbits.RandomOffsetFactor;
r /= 1 + r;
var f = orbits.Yr / (orbits.Y1 * orbits.Y1 * s);
this.calc = function(id, iw)
{
var mod = this.t * r;
return this.t - id.code % mod - f * iw.product();
}
}
var iop = new InnerOrbitalPeriod(this, iw.s);
function OuterOrbitalPeriod(orbits)
{
this.t = orbits.Yr;
var r = orbits.RandomOffsetFactor;
var f = orbits.Yr;
this.calc = function(id, ow)
{
var t = this.t + 0.5 * f * ow.product();
var mod = t * r;
if (mod != 0)
t += id.code % mod;
return t;
}
}
var oop = new OuterOrbitalPeriod(this);
// Grrr, need an index sorted by Entity.ID as planets[] order may
// change on different system entries.
var planetsarray = this.mkPlanetIndex();
var today = clock.days + id.code;
var a = 2.0 * Math.PI * (today % this.Yr) / this.Yr;
var info = (180 * a / Math.PI).toFixed();
this.Log(this.Verbose, system.name + ":" +
today + "," +
ow.p.toFixed(4) + "," +
ow.s.toFixed(4) + "," +
(pm.radius / 10).toFixed()+ "," +
(180 * a / Math.PI).toFixed());
// Pretend to rotate the main planet.
var pmOffset = pm.position.subtract(pv.position(a, 1));
for (var i = 0; i < planetsarray.length; ++i)
{
var pi = planetsarray[i];
if (pi.isMainPlanet || this.isMoon(pi))
continue;
iw.c = ow.c = map.interpolate(pi.radius);
id.nextPrime();
id.calcCode();
// Current planet's days per year. Try to make it an inner
// planet. If that fails it will be an outer planet.
var d;
var t = iop.calc(id, iw);
var inner = t > this.Yr / 3;
if (inner)
{
// Orbit Radius in planet-sun units (3. Kepler's law)
d = pow(t / this.Yr, 2.0 / 3.0);
inner =
// idea: 0.3 * pv.dist / pm.r <= d * pv.dist / pi.r
pm.radius * d >= pi.radius * 0.3 &&
d * pv.dist > 15 * s.radius;
}
if (!inner)
{
t = oop.calc(id, ow);
d = pow(t / this.Yr, 2.0 / 3.0);
}
// Current angle in radians
var a = 2.0 * Math.PI * (today % t) / t;
var aa = (180.0 * a / Math.PI).toFixed();
this.Log(this.Verbose,
system.name + "[" + i + "]" + ":" +
id.prime + "," +
id.code + "," +
(pi.radius / 10).toFixed() + "," +
ow.c.toFixed(4) + "," +
t.toFixed() + "," +
d.toFixed(4) + "," +
aa);
pi.position=pv.position(a, d).add(pmOffset);
if (inner)
{
iw.next(), iop.t = t, ++this.innerPlanets;
info = aa + "," + info;
}
else
{
ow.next(), oop.t = t, ++this.outerPlanets;
info = info + "," + aa;
}
}
s.position=(s.position.add(pmOffset));
this.info = info;
}
To go into a bit of detail, the stranger's script uses the witchpoint buoy to get the witchpoint's position. My script calls this code before buoy appears in the system, which causes the code to exit without doing anything to the system.
Since the witchpoint is always the start of absolute coordinate system - (0, 0, 0) , it can simply be written directly in the script itself.
@stranger, could you consider updating the Planetary System with this suggestion?
dybal wrote: ↑Wed Aug 24, 2022 3:55 pm
You might put Planetary System OXP as required in the manifest, and test SW_PS_script and quit if undefined (if PS is installed, that would mean a syntax error in its script).
Great suggestion, thanks for the reminder! I'll add it in the next version if I ever get around to it.
By the way, this oxz is entirely the result of a midnight insight, so I didn’t really pay attention to everything else, except, in fact, the working capacity of the solution.
dybal wrote: ↑Wed Aug 24, 2022 3:55 pm
I suggest testing with an OXP solar positioned deterministic station (like Kiota Solar Station from WildShips OXP - even if the commies states deterministic:true in the populator settings in systemWillPopulate, I don't remember ever being able to save a game there... I don't know why, but I'm looking into it): while in the main station, spend time enough for the day to change (I suggest buying and installing something), then going to the OXP station, docking there, saving the game and reloading the savefile to see if anything breaks... the station coordinates when the system populates in the reload will be based on different orbit positions (since the day changed) from those when the savefile was created... you might yourself in the main station after reloading
I can confirm that such a teleportation to the main station is indeed possible, however, according to my observations, it seems that it will take more than a day in the one system to get this. And thanks for the suggested stations.
Regarding stations from Commies, this was one of my fears that could break my solution, but since it showed up even without this tweak, I just assumed save/load broke something else from my oxp.
You are welcome!
I would like to note that I also did this to a great degree for myself - I have been using this part of SW World for some time already and was already thinking about giving it up, because before this thread I thought that nothing could be done about this throwing OXP stations and waypoints into middle of nowhere.