[Jongware]
Most recent update (All By Hand(TM)): 1-Apr-2006 01:04

 

Here we are: Born to be kings,
we're the princes of the universe!
Here we belong, fighting to survive,
on a world with the darkest powers ...

Queen, Princes of the Universe

 

The Frontier Galaxy II: Distant Suns

The randomness of the game turns against its creators if you want sensibly named stars and planets in the game. So you just mess up the randomness by comparing your parameters against some predefined values -- at a penalty for speed, by the way. Frontier uses four different strategies to create not-so-random systems. Each of the four possibilities must be checked before you can display just about anything. Even more important is the time to check -- before, during, or after a sector is generated, before, during, or after a single star is defined, and before etc. you can see a single humble planet. Let's step trough them one by one, shall we.

Strategy #1: This Sector is Mine

There is a number of sectors containing absolutely no random stars at all. Each and every star in those -- as well as some other objects not to be found anywhere else in the galaxy -- are defined in some tables, of which the sector list is the most important. The sector list (I call it the KnownSpaceCoord, it occupies roughly the same space as Larry Niven's "Known Space") is a list of absolute sector coordinates which all have something special. If a given sector is in this list just forget about the random generating thingy, and look up the data in a table.

Let's forget about fancy color-coded source for a while -- it's just a list of numbers anyway. (Being coordinates rather than a single array, I should display it nicely formatted into two columns -- but that eats tons of screen real estate and is a bore to read anyway.)

KnownSpaceCoord[49][2] = {
	5912,5412, 5913,5412, 5913,5413, 5912,5413, 5911,5413, 5911,5412, 5911,5411,
	5912,5411, 5913,5411, 5914,5411, 5914,5412, 5914,5413, 5913,5414, 5912,5414,
	5911,5414, 5910,5413, 5910,5412, 5910,5411, 5911,5410, 5912,5410, 5913,5410,
	5909,5414, 5917,5414, 5917,5411, 5913,5408, 5916,5416, 5918,5416, 5918,5406,
	5908,5395, 5906,5372, 5873,5378, 5971,5426, 6004,5418, 5944,5444, 5912,5488,
	5766,5497, 5908,5422, 5912,5417, 5912,5416, 5913,5418, 5914,5417, 5915,5417,
	5909,5419, 5909,5406, 5910,5406, 5909,5407, 5908,5407, 5908,5406, 5910,5416 };

Readers of the previous part will notice that these coordinates all are grouped around the first coordinate (5912,5412), and, indeed, there is something special about this one, remember? It's the sector containing good old Sol, and, anthropocentric as we are (and apparently Federal to boot), in the game this is the sector (0,0).

Now what special treats can we find in those sectors? Two things: they contain a number of predefined stars on predefined 3d coordinates (that number may actually be '0'), and they may contain a special object. Special objects in this sense are:

  • Galactic nebulae (nice round and fluffy in FE2, butt ugly scaled bitmaps in FFE)
  • One-lightyear high texts proclaiming "CORE", "SYSTEMS", "IMPERIAL SYSTEMS", and -- in FFE -- "ALLIANCE"
  • Nice purply lines depicting the rather useless trade routes around Sol
Note: These objects are defined in the 3D Object List of the programs. Apparently they may be mixed freely with the drawing of stars on the galactic map -- the green grid itself is one of the other objects. Also note: In the 3D Object List there is one with 64 vertices but no actual drawing data, and seems to be filled with star coordinates and then drawn as any other object.

The list of so-called 'special objects' is as long as the Special Sector list: 49 elements, every number signifying a single special object. The numbers here do not mean anything if you don't know how the 3D Object List works. Suffice to say that every 3D object in the entire game from Proximity Mine up to Red Giant Star is defined in one gigantic list. Maybe I'll tell you all about that later (it's not gonna be today or even tomorrow!).

Since there may also be no special in a sector this is indicated by a '0', and the sector in question is interesting only because of its stars. Oh, and a side effect is of course that there can't be more than one special object in any given sector...

SpecialObjects[49] = {
	168,	// text "CORE" and trade routes
	341,	// text "SYSTEMS"; more trade routes
	0, 0, 0,
	342,	// some trade routes
	343,	// some more trade routes
	173,	// fluffy space clouds
	0, 0, 0, 0, 0, 0, 0, 0,
	344,	// and some more trade routes
	173,	// fluffy space clouds
	0, 0, 0, 0, 0, 0,
	345,	// Text "IMPERIAL SYSTEMS"
	0, 0, 0, 0, 0, 0, 0, 0,
	173,	// .. and more fluffy clouds
	0, 0, 0,
	173,	// .. and some more fluffy clouds
	173,	// .. and still more fluffy clouds
	0, 0, 0, 0, 0, 0, 0,
	173,	// .. more fluffy clouds
	173,	// .. and some unexpected ones! (*)
	174		// Text "ALLIANCE"
};

(*) Due to some programming error -- I presume -- the systems in this sector (-4,-6) which DID appear in Frontier have gone up in smoke in FFE!

 

Didn't I just say you can't have more than one 'object' in every sector? Both texts "CORE" and "SYSTEMS" and their associated trade routes are single 3D objects. Now that's cheating, isn't it?

 

Each of these sectors may also contain stars, and these and their coordinates are defined in a few other lists. For historic reasons (David's, not mine) the data is spread over a few arrays instead of one, making life a tad more complicated than necessary.

The names of the stars (consecutive stars are in the same sector):

char *KnownSpace[117] = {
	"Sol",			// Start of sector (0,0)
	"Alpha Centauri",
	"Wolf 359",
	"Lalande 21185 ",
	"UV Ceti",
	"Ross 128",
	"Tau Ceti",
	"LET 118",
	"Wolf 424",
	"CD-37º15492",
	"Lalande 25372",
	"Sirius",			// sector (1,0)
	"Epsilon Eridani",
	"Procyon",
	"BD+5º1668",
	"BD+20º2465",
	"Groombridge 1618",	// 1,1
	"Luyten 1159-16",
	"WX Ursa Majoris",
	"+53º1320",
	"Ross 248",			// 0,1
	"Groombridge 34",
	"van Maanens Star",
	"Giclas 158-27",
	"61 Cygni",			// -1,1
	"Struve 2398",
	"1º4774",
	"Barnards Star",	// -1,0
	"Ross 154",
	"Luyten 789-6",
	"Lacaille 9352",
	"Lacaille 8760",
	"Ross 780",
	"Fomalhaut",
	"Epsilon Indi",		// -1,-1
	"BD 4523",
	"CD-46º11540",
	"CD-49º13515",
	"CD-44º11909",
	"-11º3759",
	"Kapteyns Star",	// 1,-1
	"82 Eridani",
	"Luyten 674-15",	// 2,-1
	"Ross 614",			// 2,0
	"Omicron Eridani",
	"YZ Canis Minoris",
	"-21º1377",
	"HD 36395",
	"LP 658-2",
	"Ross 986",			// 2,1
	"Ross 47",
	"Wolf 294",
	"Stein 2051",		// 1,2
	"AC+79º3888",		// 0,2
	"Eta Cassiopeia",
	"Krüger 60",		// -1,2
	"BD 946",
	"BD+43º4305",
	"Sigma Draconis",
	"+19º5116",
	"Altair",			// -2,1
	"FU 46",
	"70 Ophiuchi",		// -2,0
	"VB 10",
	"Arcturus",
	"36 Ophiuchi",		// -2,1
	"HR 7703",
	"Luyten 347-14",
	"Wolf 630",
	"Delta Pavonis",	// -1,-2
	"Luyten 205-128",
	"-40º9712",
	"-45º13677",
	"Luyten 145-41",	// 0,-2
	"Beta Hydri",
	"Luyten 97-12",		// 1,-2
	"Vega",				// -3,2
	"Castor",			// 5,2
	"Pollux",
	"Regulus",			// 5,-1
	"Achenar",			// 1,-4
	"Capella",			// 4,4
	"Aldebaran",		// 6,4
	"Canopus",			// 6,-6
	"Spica",			// -4,-17
	"Hadar",			// -6,-40
	"Antares",			// -39,-34
	"Betelgeuse",		// 59,14
	"Rigel",			// 92,6
	"Alcyone",			// 32,32; the Pleiades
	"Atlas",
	"Electra",
	"Maia",
	"Merope",
	"Taygete",
	"Pleione",
	"Polaris",			// 0,76
	"Beta Lyrae",		// -146,85
	"Alkaid",			// -4,10
	"Mizar",			// 0,5
	"Alcor",
	"Alioth",			// 0,4
	"Megrez",			// 1,6
	"Phekda",			// 2,5
	"Merak",			// 3,5
	"Dubhe",			// -3,7
	"Lave",				// -3,-6; some original Elite systems
	"Diso",
	"Riedquat",
	"Leesti",
	"Orerve",
	"Zaonce",			// -2,-6
	"Tionisla",
	"Reorte",			// -3,-5
	"Uszaa",
	"Orrere",
	"Quator"
};

Side note: in the executables "Krüger 60" appears as "Kr]ger 60", and the "º" in names as "CD-37º15492" appears as "^" but that's just the original bitmap font. For your convenience I've translated these to regular characters.

 

The location of the stars in coords_t format:

coords_t KnownSpaceStarCoords[117] = {
	{  0,  16,  -54,  0x84,   0 },	// #0: Sol
	{-15, -52,  -52,  0x84,   2 },	// #1: Alpha Centauri
	{ 58, -19, -127,     1,0x18 },	// #2: Wolf 359
	{ 47,  40, -127,     1,0xF8 },	// #3: Lalande 21185
	{ 27,  38,  83,      0,   1 },	// #4: UV Ceti
	{ 48, -58, -127,     1,0xC8 },	// #5: Ross 128
	{ 41,  52,  127,     4,0x10 },	// #6: Tau Ceti
	{ 14,  52,  127,     1,0xE0 },	// #7: LET 118
	{ 18, -56, -127,     1,0xB9 },	// #8: Wolf 424
	{-38, -24,  127,     1,0xE8 },	// #9: CD-37º15492
	{-55, -36, -127,     1,0xC8 },	// #10: Lalande 25372
	{  5, -17,  -32,  0x86,   1 },	// #11: Sirius
	{-19,  51,   72,     3,0x78 },	// #12: Epsilon Eridani
	{ 49,  13,  -94,     5,0x29 },	// #13: Procyon
	{ 63,  18,  -88,     1,0xE8 },	// #14: BD+5º1668
	{ 21,   5, -127,     1,0xF8 },	// #15: BD+20º2465
	{-27,  -6, -127,     3,   0 },	// #16: Groombridge 1618
	{-59,  44,  123,     1,   0 },	// #17: Luyten 1159-16
	{-37, -26, -127,     0,   1 },	// #18: "WX Ursa Majoris"
	{ 26,  57, -127,     1,   1 },	// #19: +53º1320
	{-36,  42,   -8,     1,0x48 },	// #20: Ross 248
	{-20,  63,    2,     1,0xEA },	// #21: Groombridge 34
	{ -3,   9,  127,     7,0xA0 },	// #22: van Maanens Star
	{-45, -35,  127,     1,0x28 },	// #23: Giclas 158-27
	{ 11,  23,  -37,  0x83,0x71 },	// #24: 61 Cygni
	{ 35,  26, -127,     2,0xF1 },	// #25: Struve 2398
	{ 47,  32,  127,     1,0x30 },	// #26: 1º4774
	{ 37,  12,  -77,     2,   8 },	// #27: Barnards Star
	{-11, -39,  -26,  0x82,0xD0 },	// #28: Ross 154
	{ 36,  40,   90,     1,0x58 },	// #29: Luyten 789-6
	{ 60, -18,  116,     1,0xF8 },	// #30: Lacaille 9352
	{  2, -52,   85,     1,0xF8 },	// #31: Lacaille 8760
	{  7,  59,  127,     1,0xF0 },	// #32: Ross 780
	{-16, -10,  127,     6,0x28 },	// #33: Fomalhaut
	{ 62,  45,   79,     3,0x50 },	// #34: Epsilon Indi
	{-38,  48, -127,     1,0xE1 },	// #35: BD 4523
	{-26, -39,  -24,     1,0xF8 },	// #36: CD-46º11540
	{  6,  29,  122,     1,0xD8 },	// #37: CD-49º13515
	{-37, -34,  -24,     1,0xC8 },	// #38: CD-44º11909
	{ -9, -52, -127,     1,0x80 },	// #39: -11º3759
	{  2,  46,   66,     2,0xF0 },	// #40: Kapteyns Star
	{ 13,  36,  127,     4,0x40 },	// #41: 82 Eridani
	{ 11,   0,  -87,     1,0x80 },	// #42: Luyten 674-15
	{-48,  16,  -31,     1,   1 },	// #43: Ross 614
	{-61,  60,  102,     4,   2 },	// #44: Omicron Eridani
	{ 32,   3, -119,     0,   0 },	// #45: YZ Canis Minoris
	{ 17, -58,   42,     2,0xF8 },	// #46: -21º1377
	{ 31,  48,   48,     2,0xF8 },	// #47: HD 36395
	{ 47,  32,   24,     7,0x78 },	// #48: LP 658-2
	{-16,  49, -127,     1,0x18 },	// #49: Ross 986
	{ 32,  -9,   -4,     1,0x38 },	// #50: Ross 47
	{  3,  37, -127,     1,0xF8 },	// #51: Wolf 294
	{-14,   4,  -90,     2,0x21 },	// #52: Stein 2051
	{ 14, -30, -127,     1,0xC8 },	// #53: AC+79º3888
	{ -2,  63,  -30,  0x84,   1 },	// #54: Eta Cassiopeia
	{ 63, -46,  -56,     2,0x9A },	// #55: Krüger 60
	{ 40, -46, -127,     1,0xC0 },	// #56: BD 946
	{ 27,   4,    4,     1,0x90 },	// #57: BD+43º4305
	{ 26,  13, -127,     3,0x88 },	// #58: Sigma Draconis
	{  7,  -3,  127,     1,0x19 },	// #59: +19º5116
	{  2, -46,  -15,     6,0x10 },	// #60: Altair
	{ 43,  54, -127,     1,0xB1 },	// #61: FU 46
	{ -5,   0, -107,     3,0xAA },	// #62: 70 Ophiuchi
	{-54,  56,  -38,     2,0xE9 },	// #63: VB 10
	{ 60, -56, -127,     8,   0 },	// #64: Arcturus
	{ 25, -16,  -87,     3,0x72 },	// #65: 36 Ophiuchi
	{ 32,  28,   97,     3,0x11 },	// #66: HR 7703
	{ 49, -32,   67,     1,0xA0 },	// #67: Luyten 347-14
	{-24,  29, -127,  0x82,0xEC },	// #68: Wolf 630
	{ 15,  49,  107,     4,0x70 },	// #69: Delta Pavonis
	{-30,  21,   24,     1,   8 },	// #70: Luyten 205-128
	{-20,   9, -116,     1,0xF8 },	// #71: -40º9712
	{ 46, -20,  119,     1,0x28 },	// #72: -45º13677
	{ 31,  22,  -38,     7,0x48 },	// #73: Luyten 145-41
	{ -8,  22,  127,     4,0x88 },	// #74: Beta Hydri
	{-17,  10,   49,     7,0x50 },	// #75: Luyten 97-12
	{ 52, -20, -127,     6,0x68 },	// #76: Vega
	{ 14, -63, -127,     6,0x15 },	// #77: Castor
	{-64, -38, -127,     8,   0 },	// #78: Pollux
	{ 59, -40, -127,  0x0A,   1 },	// #79: Regulus
	{ -4, -16,  127,  0x0A,   0 },	// #80: Achenar
	{-52, -36, -111,     8,   3 },	// #81: Capella
	{ -1, -16,  127,     8,   1 },	// #82: Aldebaran
	{-55,  -9,  127,     9,   0 },	// #83: Canopus
	{-16, -12, -127,  0x0A,   1 },	// #84: Spica
	{-33, -48,  -85,  0x0C,   0 },	// #85: Hadar
	{ 37, -57, -127,  0x0B,   1 },	// #86: Antares
	{-16, -32,  127,  0x0B,   1 },	// #87: Betelgeuse
	{ 16,  48,  127,  0x0C,   1 },	// #88: Rigel
	{-16, -32,  -54,     9,   1 },	// #89: Alcyone
	{ 56, -16,  -54,  0x0A,   1 },	// #90: Atlas
	{-56,   0,  -46,  0x0A,   0 },	// #91: Electra
	{ 32,  16, -102,  0x0A,   0 },	// #92: Maia
	{ 16,  32,  -22,  0x0A,   0 },	// #93: Merope
	{ 48,  48, -118,  0x0A,   0 },	// #94: Taygete
	{-59, -64,  -62,  0x0A,   0 },	// #95: Pleione
	{ 52, -33, -127,     9,   0 },	// #96: Polaris
	{-16,  16, -127,  0x0D,   0 },	// #97: Beta Lyrae
	{-19,  -4, -127,  0x0A,   0 },	// #98: Alkaid
	{ 16,  22, -127,     6,   1 },	// #99: Mizar
	{ 18,  21, -127,     5,   1 },	// #100: Alcor
	{ -5,  56, -127,     9,   0 },	// #101: Alioth
	{-24,  44, -127,     6,   1 },	// #102: Megrez
	{-62,   6, -127,  0x0A,   0 },	// #103: Phekda
	{ 44,  -4, -127,     6,   0 },	// #104: Merak
	{-31, -48, -127,     9,   1 },	// #105: Dubhe
	{ 48,  48,    0,  0x83,   0 },	// #106: Lave
	{ -9,  45,    0,  0x84,   0 },	// #107: Diso
	{-60,  35,    0,  0x84,   0 },	// #108: Riedquat
	{  3,   6,    0,  0x82,   0 },	// #109: Leesti
	{ -3, -48,    0,     4,   0 },	// #110: Orerve
	{  3,  10,    0,  0x85,   0 },	// #111: Zaonce
	{ 35, -16,    0,     4,   0 },	// #112: Tionisla
	{ 47,  -9,    0,     4,   0 },	// #113: Reorte
	{-60, -16,    0,     4,   0 },	// #114: Uszaa
	{-41,  16,    0,     4,   0 },	// #115: Orrere
	{ 10,  35,    0,     4,   0 },	// #116: Quator
};

In this list you can see values in the unused bits of the stardesc and multiple members. I once had an idea what that was for but I forgot! So it's probably not that important.

This is the list as it appears in FFE. In FE2 the coordinates for the Pleiades are different -- uglier to be precise. They appear there as

	{-16,  16,  -54,     9,   1 },	// #89: Alcyone
	{ 56,  16,  -54,  0x0A,   1 },	// #90: Atlas
	{-56,  16,  -46,  0x0A,   0 },	// #91: Electra
	{ 16,  16,  -22,  0x0A,   0 },	// #93: Merope
	{ 48,  16, -118,  0x0A,   0 },	// #94: Taygete
	{-59,  16,  -62,  0x0A,   0 },	// #95: Pleione

... and the order of the struct members is a bit different too (smoothed out here).

But wait! There are 117 predefined names and 117 predefined positions, so I could match star name to star coordinate. How on earth do you cram that in the 49 predefined sectors defined previously? Use a table!

KnownSpaceName[] = {
	0, 11, 16, 20, 24, 27, 34, 40, 40, 42, 43, 49, 52, 53,
	55, 60, 62, 65, 69, 73, 75, 76, 77, 79, 80, 81, 82,
	83, 84, 85, 86, 87, 88, 89, 96, 97, 98, 99, 101, 102,
	103, 104, 105, 106, 111, 113, 117, 117, 117, 117, 117,
	117
};

Yes, yes, I know this list has 52 elements -- someone not too sure about overflows, perhaps?

 

To find star System Number N in sector X,Y scan through the list of defined sectors "KnownSpaceCoord" for (X,Y); if it's there take the offset Off from that position in KnownSpaceName. Now your system number N should be between KnownSpaceName[Off] and KnownSpaceName[Off+1] - KnownSpaceName[Off]; if it isn't that system number does not exist. If it is, it's name is at KnownSpace[KnownSpaceName[Off]+N] and its coordinates and stellar parameters are in KnownSpaceStarCoords[KnownSpaceName[Off]+N]. Be careful: N may not be more than the actual number of stars in the sector, and there may also be zero stars in that sector. Left as an exercise for the programmer, I guess.

 

Recap: if you want to display ANY sector at all you'll first have to check if it is a predefined one, and if so, copy all coordinates for that sector into your coords_t array. Otherwise, you can generate it at random and get on with it.

Strategy #2: This System is Mine

If you understood the above you'll be able to deduce by now that each and every single star in the entire galaxy can be generated and identified by three numbers: sector x, sector y, system number. The sector x and y numbers each fit into 13 bits, and the system number (0..62) fits into 6 bits. Hey.. let's combine all of'em into one large 32-bit dword. The correct method appears to be (SystemNumber<<26) + (SectorY<<13) + (SectorX), resulting in a single unique identifier for every single star in the entire galaxy! Gasp! So we can do interesting things with it. Such as identifying a single unique star by number (that's the other way around). Time for another table. It uses this structure, full of unknown items.

struct {
	unsigned long UniqueId;
	unsigned char Population;
	unsigned char techlevel,c;
	unsigned char Chance_CargoCheck;
	unsigned char d,e;
	unsigned short Government_Allegiance;
	unsigned char danger;
	signed char item_status[31];
	unsigned char FedImpCheck,i;
	int WorldDesc;
	int LongDesc;
} PredefinedSystem_t;

I must admit that not every parameter is clear to me; the meaning of the unsigned chars b,c,d,e,g,h and i is totally obscure at the mo. The others seem to be used as follows:

UniqueId: the identifier for the star

Population: numbers one of the following strings:
"None registered",
"Less than 1,000",
"1,000-10,000",
"10,000-100,000",
"100,000-1 Million",
"1-10 Million",
"10-100 Million",
"100 Million-1 Billion",
"1-10 Billion",
"More than 10 Billion"

techlevel: A value from 0..255 telling you what highest tech equipment you can buy. Every piece of equipment has a "required" tech level in the same range. If that's lower or equal: buy it here. Higher: forget it.

Chance_CargoCheck: Used in the 'smuggling' scenario, hence the name. The chance of getting caught is a random number between 0..7. If this value is lower, you got out. Larger or equal means you're busted. So '0' is a small chance (1 in 8) and 7 is 100% sure. Achenar(1,-4) even has an '8' here -- not a chance!

Government_Allegiance & 0x3f: one of the following strings:
"None",
"None (Anarchy)",
"Rule by force of local Barons",
"Policed by the local corporations",
"Corporate State",
"Federal Democracy",
"Federal Colonial Rule",
"Dictatorship",
"Communist",
"Religious Dictatorship",
"Independent Democracy",
"Imperial Rule",
"Imperial Colonial Rule",
"No Stable Government",
"Martial Law",
"Alliance Democracy"

(Government_Allegiance >> 6) & 7: one of the following strings:
"Independent",
"Imperial",
"Federation",
"Alliance",
"None"

danger: a copy of Government_Allegiance values, though not all values are used: 1=Rule by force of local Barons, 2=Anarchy, 5=Civil War, 7=No Stable Government. Used, together with the Population value and the item_status array, to calculate the amount of variance in trade good prices. See also John Jordan's commented sources (that's where I got the Trade part from!).

item_status: There are 31 values here, enumerated as in the well-known cargo list "Water", "Liquid Oxygen", "Grain", "Fruit and Veg.", "Animal Meat", "Synthetic Meat", "Liquor", "Narcotics", "Medicines", "Fertilizer", "Animal Skins", "Live Animals", "Slaves", "Luxury Goods", "Heavy Plastics", "Metal Alloys", "Precious Metals", "Gem Stones", "Minerals", "Hydrogen Fuel", "Military Fuel", "Hand Weapons", "Battle Weapons", "Nerve Gas", "Industrial Parts", "Computers", "Air Processors", "Farm Machinery", "Robots", "Radioactives", "Rubbish", and "Alien Artefacts".
The 32nd item is "Chaff", and due to some stoopid error this is not included in the actual item_status but is written to the system Trade info screen, so every system appears to export Chaff!
Possible values per item are 3..4: Minor Import, 5..7: Major Import, 11..12: Minor Export, 13..15: Major Export (bit 3 determines if something is either import or export). If bit 7 is set: Illegal!

FedImpCheck: The lower 4 bits of this byte determine the strength of the Federation Military in the system, from 0..10. The higher 4 bits do the same for the Imps. Used to generate Military missions; see Zeaex (3,-2), which scores 4/4 and is known as "Disputed system".

WorldDesc: subtract 0x84E5, then one of the following strings:
"Unexplored system. No more data available.",
"System explored. No registered settlements.",
"Frontier system. Some prospecting and mining.",
"Some small scale mining operations.",
"Mining and some ore refinement.",
"Mining and heavy manufacturing industry.",
"Extensive mining and industrial development.",
"No Planets. No registered settlements.",
"Rare element and reactor fuel production.",
"Frontier outdoor world. Some farming and tourism.",
"Outdoor agricultural world. Federation member.",
"Outdoor ice and water world. Tourism and fishing.",
"Outdoor jungle world. Tourism and agriculture.",
"Outdoor desert world. Some agriculture.",
"Isolationist religious enclave. Permit required.",
"Strict communist regime. Permit required.",
"Federal prison colony. Permit required.",
"System under Federal interdict. Illegal to visit.",
"Scientific research station.",
"Terraformed agricultural world.",
"Terraformed garden world. High-cost tourism.",
"Terraformed ice and water world. Tourism.",
"Two terraformed agricultural worlds. Tourism.",
"High population outdoor world. Federation member.",
"Historic Federal capital. Administration and Tourism.",
"Imperial capital. Seat of the Emperor.",
"High population outdoor world under Imperial rule.",
"Imperial industrial and mining colony.",
"Imperial terraformed world.",
"System of special scientific interest.",
"Outdoor world. Independent Dictatorship.",
"Anarchic system. Minimal police protection.",
"Disputed system.",
"Imperial outdoor worlds and naval base.",
"Federal naval base.",
"Corporate ice world.",
"Alliance Industrial and Mining System.",
"Capital of the Alliance.",
"High Population Alliance System."

LongDesc: subtract 0x8000, then one of the following strings:
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
"Famous as the first true corporate system. The Sirius corporation has been using the vast amounts of cheap energy available on Lucifer from coils wrapped around the planet for synthesis of custom elements (particularly military grade fuel) since 2350 and the first interstellar war.\rThis system is not subject to Federal law.",
" ",
"Landfall has one of the most interesting skies of all the known habitable planets, with no less than six stars bright enough to cast shadows at some time.\rIt also has the best preserved indigenous wildlife which cohabits succesfully, often to the exclusion of introduced life.",
" ",
"Very high humidity and native life make this an interesting place to visit. Many exotic food stuffs are grown here. The scenery is strikingly beautiful, though the wildlife can be a little dangerous.",
"Only just sustaining life, the indigenous forms on this arid planet are very hardy.",
"This system was given to the Guardians of the Free Spirit religious sect by the Federation in 2480. They believe in maximum hardship and live underground on several of the inner planets of the system. It is forbidden by Federal Law to enter the system without the permission of the Guardians.",
"Famous as the first flare star system to be settled, in 3017. All surface habitations have flare shelters beneath them, which should be entered on hearing the flare warnings. The first planet, often known as Lenin, was terraformed by a group of rich idealists on condition it was run to strict communist principles. They endowed an enormous amount of wealth to the system, which is now very rich.",
"Prisoners are housed in underground cell complexes, and set to do manual mining work. Visitors are allowed, but an entry permit must first be obtained.\r There is reputed to be a seedier side to the colony whereby lonely visitors may enter without a permit while the guards turn a blind eye for a fee, but this is always denied.",
" ",
"Eden was the first planet on which liquid water was detected, by spectroscopic methods in 2038, and so was a major driving force for the exploration of space. However, Eden turned out to be extremely inhospitable with the added danger of hard radiation from Proxima. There is now a small research station on Eden, but little else in the rest of the system.",
"Vast areas are used for growing custom grain crops in enormous quantities which are then exported to the surrounding worlds.No manufacturing industry is permitted to avoid any polluting emmisions.",
"The inner planet was terraformed by the Cisco corporation into a beautiful theme park in 2958. The system does not come under Federal law, and a wide range of exotic delights are available, including historic adventures staged using actors.",
"The planet Scott was terraformed in 2329 as an agricultural colony, but the temperature could not be sustained and was abandoned in 2408 after a disease epidemic. The equatorial belt was resettled in 2641 by settlers who liked the harsh environment, now famous for fishing and tourism. It is particularly popular with the industrial workers from nearby systems who otherwise live their whole lives indoors.",
"Two planets here have now been terraformed, and both are largely given over to agricultural production and to ethically questionable cattle ranching. There is little manufacturing industry other than the production of the famous bourbon.",
" ",
"First colony outside the Sol system, and first alien life was discovered here. Unfortunately the last remnants are now in zoo enclosures for tourists, introduced life and crops cover most of the surface and seas.",
"Early life had just started to emerge on Arcturus 3 when the human settlers arrived in 2304. This has now been replaced by an Earth ecosystem, adapted to live under the red light. Locals are generally confident their star will remain a red giant forever.",
"Historic system famous as both the birthplace of Humanity and as the political capital of the Federation. A very expensive and prestigious system to live in, and a popular tourist venue. Most rich humans will visit Earth once in their lives. All the major corporations have their headquarters on Mars, terraformed in 2286, which is the main centre for administration.",
"Imperial capital on Achenar 6d, known as Capitol by the locals. 6c is still known as Conversion though it was terraformed in 2696. 6b was terraformed in 2850 to accomodate the population explosion which followed. Anyone without the quirky accent of Imperial citizens is shunned, especially if they are from a Federation world.",
"The system relies heavily on slavery to maintain the luxurious life style of the very wealthy élite. Most live on the great plantations, common throughout the Imperial Worlds. The cities house the workers for the service industries and the more exotic entertainments.",
"The deep and highly mechanised Imperial mines are renowned for their efficiency at ore extraction. Slavery is also important for the routine supervision of the machinery in the unpleasant mining environment.",
"Many Imperial worlds were terraformed during the last major Imperial expansion 2950-3150, including this, and there are numerous fine examples of architecture of the period.",
" ",
" ",
"There is no real law here, though in the cities organised crime does some form of policing. It is highly recommended to avoid this system if at all possible.",
" ",
"Well known Imperial Naval Base. Most Imperial naval administration is done on Topaz, and there are several outdoor training camps across the surface.",
"The main Federal Naval Base was moved here from Anlave in 2983 following terraforming in the 2970s, and is an excellent training ground for planetary assault troops.",
"System most famous for the giant Verrix. Stevenson is the home world of the hardy beast of burden now found throughout human space, especially on the emerging worlds of the outer rim.",
"The Industrialised worlds of the Alliance are well known for the far better conditions available for workers than elsewhere.",
"The now famous capital of the Alliance of Independent Systems. This system was the subject of many battles between the Federation and the Empire over many years, until in 3230 the Alliance was formed in a massed insurrection against both sets of invaders.\rThe Alliance has now spread over many worlds, and so Alioth is now an important political centre.",
" ",
" ",
" ",
" "
Note that the single spaces indeed appear in the original code. Apparently there is nothing remarkable about those systems except they use up space.

 

The odd numbering in which the text strings are biased by 0x8000 and 0x84E5 is because these strings are part of the global game string pool in which each and every text string can be found. Don't think about that for now; where possible I've flattened them out.

All this data is indexed for stars through its UniqueId in the following list. Each single element describes a single star, identified by its Unique Id number, and it doesn't matter whether the star by that number is predefined or random generated.

PredefinedSystem_t PredefinedSystems[] = {
{ 0x02A49718, 0, 0x00, 0, 0, 0, 0, 0x00, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0,
	0x84E5, 0x8000 }, 	// Sol (0, 0)
{ 0x02A49718, 0, 0x02, 0, 0, 0, 0, 0x00, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0
	0x84E6, 0x8001 }, 	// Sol (0, 0)
{ 0x02A49718, 1, 0x0C, 5, 0, 0, 3, 0x01, 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0,
	0x84E7, 0x8002 }, 	// Sol (0, 0)
{ 0x02A49718, 1, 0x33, 4, 0, 1, 7, 0x01, 2, 0x05, 0x05, 0x03, 0x05, 0x02, 0x03,
	0x03, 0x03, 0x03, 0x00, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x0B, 0x0B, 0x0E,
	0x03, 0x00, 0x02, 0x01, 0x01, 0x03, 0x01, 0x02, 0x00, 0x02, 0x00, 0x00, 0, 0,
	0x84E8, 0x8003 }, 	// Sol (0, 0)
{ 0x02A49718, 2, 0x6E, 3, 1, 4, 9, 0x03, 0, 0x05, 0x05, 0x03, 0x05, 0x02, 0x05,
	0x03, 0x03, 0x03, 0x01, 0x01, 0x00, 0x02, 0x03, 0x01, 0x0E, 0x0C, 0x0B, 0x0D,
	0x0A, 0x01, 0x02, 0x01, 0x01, 0x05, 0x01, 0x02, 0x00, 0x02, 0x01, 0x00, 0, 0,
	0x84E9, 0x8004 }, 	// Sol (0, 0)
{ 0x02A49718, 3, 0x8C, 3, 2, 6, 7, 0x04, 0, 0x03, 0x03, 0x03, 0x06, 0x03, 0x0B,
	0x03, 0x0B, 0x0B, 0x0E, 0x02, 0x02, 0x02, 0x03, 0x0D, 0x0C, 0x0C, 0x0C, 0x03,
	0x0A, 0x01, 0x0C, 0x0A, 0x09, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x02, 0x01, 0, 0,
	0x84EA, 0x8005 }, 	// Sol (0, 0)
{ 0x02A49718, 4, 0xCC, 1, 3, 7, 4, 0x04, 0, 0x03, 0x03, 0x03, 0x07, 0x05, 0x0F,
	0x03, 0x0B, 0x0C, 0x0E, 0x02, 0x03, 0x02, 0x03, 0x0E, 0x0E, 0x02, 0x02, 0x05,
	0x0A, 0x09, 0x0C, 0x89, 0x89, 0x0F, 0x0F, 0x0E, 0x0F, 0x0F, 0x02, 0x02, 0, 0,
	0x84EB, 0x8006 }, 	// Sol (0, 0)
{ 0x02A49718, 4, 0xE6, 1, 3, 7, 4, 0xCF, 0, 0x03, 0x03, 0x03, 0x07, 0x05, 0x0F,
	0x03, 0x81, 0x0C, 0x0E, 0x02, 0x81, 0x81, 0x03, 0x0E, 0x0E, 0x02, 0x02, 0x05,
	0x0A, 0x09, 0x0C, 0x89, 0x89, 0x0F, 0x0F, 0x0E, 0x0F, 0x0F, 0x02, 0x02, 0, 0,
	0x8509, 0x8026 }, 	// Sol (0, 0)
{ 0x02A49718, 9, 0xFD, 0, 5, 9, 0, 0x85, 0, 0x00, 0x00, 0x0A, 0x0B, 0x0B, 0x02,
	0x0E, 0x81, 0x00, 0x00, 0x89, 0x89, 0x81, 0x0E, 0x03, 0x03, 0x02, 0x02, 0x00,
	0x01, 0x01, 0x81, 0x81, 0x81, 0x01, 0x05, 0x02, 0x05, 0x04, 0x81, 0x02, 5, 0,
	0x84FD, 0x801A }, 	// Sol (0, 0)
{ 0x06A49718, 3, 0x45, 0, 1, 0, 0, 0x86, 0, 0x00, 0x03, 0x02, 0x03, 0x02, 0x03,
	0x02, 0x81, 0x03, 0x00, 0x00, 0x00, 0x81, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00,
	0x03, 0x00, 0x81, 0x81, 0x81, 0x02, 0x02, 0x03, 0x02, 0x02, 0x02, 0x01, 1, 0,
	0x84F7, 0x8012 }, 	// Alpha Centauri (0, 0)
... (338 rather similar lines omitted. Click here to get the entire list)

So if you want to describe a star system with a specific ID just loop through this list and compare your UniqueId with the ones in the list.

Now hold on! The first 9 systems all have an id of '0x2A49718', which would mean that they all refer to the same star! Moreover, if you dissect the id it comes down to System Number #0 in Sector (5412,5912), or Sector(0,0) in solarcentric coordinates. Hey! It's Sol itself! Errmm.. not quite.

 

*sigh*

 

Numbers 0-7 are in fact templates for all the not-defined ones. If you wanna scan for a system start at number 8 (that's the real Sol) and work your way down. If you find your id, you're done.

If you DIDN'T find it, you'll have to consider if you are playing Frontier or FFE. In FFE there are some sectors alleged to the Alliance, and if it is one of those the predefined system you're looking for is number 7. The Allegiance sectors are

	0x2A53717,	// (-1,5)
	0x2A53716,	// (-2,5)
	0x2A53715,	// (-3,5)
	0x2A55717	// (-1,6)

Note that the System Number must be stripped off your id before comparing to these numbers (they describe sectors, not systems).

 

If playing FFE, or your sector isn't an Alliance one, the description is calculated from the distance from your system to Sol. Distance? Try this:

	xc = (UniqueId & 0x1fff)-0x1718;
	if (xc < 0) xc = -xc;
	yc = ((UniqueId >> 13) & 0x1fff)-0x1524;
	if (yc < 0) yc = -yc;
	sysnum = (UniqueId >> 26) & 0x3f;

	distance = (xc+(sysnum & 7))*(xc+(sysnum & 7));
	distance += (yc+(sysnum & 7))*(yc+(sysnum & 7));

.. so it boils down to decomposing your UniqueId into sectors and adding them up (sort of). Btw. you don't need the actual distance in light years to Sol itself so you don't have to square the result.

The distance determines which description to take:

	if (distance >= 19600) return PredefinedSystems[0];
	if (distance >= 289) return PredefinedSystems[1];
	if (distance >= 100) return PredefinedSystems[2];
	if (distance >= 49) return PredefinedSystems[3];
	if (distance >= 25) return PredefinedSystems[4];
	if (distance >= 9) return PredefinedSystems[5];
	else return PredefinedSystems[6];

If you check the WorldDesc for these systems you'll see the vague descriptions "Unexplored system", "System explored. No registered settlements", "Frontier system. Some prospecting and mining" and stuff, and governments and trade to match.

The list doesn't differ much between FE2 and FFE. The major difference is the calculation of the UniqueId; if you look into the data for FE2 you'll see that the coordinates are packed (SectorY)<<19 | (SectorX << 6) | SystemNumber. The other differences lie only in the descriptive strings: the string offsets are a bit different -- the strings for the "Alliance" obviously are missing in FE2, and (related to that), for Alioth you have 'Disputed system' instead of 'Capital of the Alliance'.

The list is expanded slightly for FFE; the last 17 systems (starting with -- not suprisingly -- Alioth) have been added.

Strategy #3: This Star is Mine

Only used when playing FFE, and only for a single star. The original code looks as if it could handle an array, so I do the same:

struct {
	unsigned long UniqueId;
	char *Name;
} ForcedNames[] = {
	0x1AA51717, "Gateway"
};

Loop through this array and check your number. If it is the same do not generate a name but copy it from the one supplied. Tee-hee. All the rest (description, planets, star type) should be generated as for any other random system.

Strategy #4: This Planet is Mine

There are just a few star systems which do not auto-generate their planets. There is an array of stars/planets which gets filled at startup with predefined values. This is how our own solar system is modelled accurately, and how a few other systems are defined. Not all parameters are clear to me, however, here listed are the items I DO understand. The most interesting fact about it it that their names aren't subject to the auto-generate routines either; so, not only we find familiar names as 'Venus' and 'Ganymede' but also 'Ridley Scott' and 'George Lucas'. Note that after a while David got bored making up planets and naming them; Diso and Leesti have only one planet, the latter imaginatively named 'Leesti 1'.

I'll just show the breakdown for Sirius, since that's one of the smaller systems. Click here to get the entire list as featured in the game.

Sirius
UniqueId: 02A49719h
Binary system. Primary: Type'A'hot white star
	0:	Sirius, Sirius B: Binary system
	1:	Sirius: Type'A'hot white star
		Mass:                  6057510 (773083.41 Earth masses)
		Surface temperature:   9000ºC
		Major starports:       None
		Co-orbital period:     17.7 years
		Separation             331448.320 AU
		Declination            0.0º
			Orbits_Around          Sirius, Sirius B
			Random_Seed            -1446069180
			ObjectNumber           143
	2:	Sirius B: White dwarf star
		Mass:                  5987701 (327966.89 Earth masses)
		Surface temperature:   11000ºC
		Major starports:       None
		Co-orbital period:     17.7 years
		Separation             331448.320 AU
		Declination            -180.0º
			Orbits_Around          Sirius, Sirius B
			Random_Seed            289548112
			ObjectNumber           148
	3:	Lucifer: Highly volcanic world
		Mass:                  4539904 (0.05 Earth masses)
		Surface temperature:   154ºC
		Major starports:       Factory Central
		Orbital period:        99 hours
		Orbital radius         0.050 AU
		Orbital Ecc. and Incl. 0.014, 38.9º
		Declination            0.0º
			Orbits_Around          Sirius B
			Random_Seed            2126207522
			ObjectNumber           122
	4:	Factory Central: City
		Surface temperature:   20ºC
		Inclination            17.8º
		Declination            121.9º
			Located on             Lucifer
			Random_Seed            1512591849
			ObjectNumber           96
	5:	Waypoint: Large gas giant
		Mass:                  5334666 (351.40 Earth masses)
		Surface temperature:   -250ºC
		Major starports:       None
		Orbital period:        3613.6 years
		Orbital radius         350.000 AU
		Orbital Ecc. and Incl. 0.283, 32.6º
		Declination            0.0º
			Orbits_Around          Sirius, Sirius B
			Random_Seed            -1260143484
			ObjectNumber           134

Wondering about 'Orbital Ecc. and Incl.'? Well it DID appear on-screen in Frontier, and the values are still there in FFE but are no longer displayed.

'Ecc.' stands for 'eccentricity', the amount of which the (theoretical) circular orbit of a planet or orbiter is flattened to an ellipse. This value is not used when drawing orbit lines in the game! Check out Pluto's orbit. David states that when viewed from above it never comes within Neptune's orbit, while general opinion (e.g., Kepler's) is that it does.

'Incl.' is the Inclination; for planets it is the angle the orbit makes through some arbitrary plane (for Sol, the plane Sol-Earth; therefore for the Earth it is by definition 0º). Declination is the angular progress the planet makes in its orbit, taken from some zero point in time; so a declination of 180º would mean the planet is half of its year on its tracks. I'm not too sure how the inclination and declination for cities are to be interpreted; surely not in the common sense, converting them to longitude and latitude? Can't figger out how to test it.

Orbital period: this is NOT, I repeat NOT coded as such anywhere in the program. But the mass of its 'parent' and the distance are given, so you can calculate it! In reality it is some floating point Newtonian calculation involving the universal gravitational constant (6.673 x 10-14 -- and that's off the top of my head), but, as David shows, some clever number shuffling comes close enough.

 

If you're curious about 'ObjectNumber': it's the 3D object used to draw the item. If you're curious about the 'Random_Seed': some planets, cities and orbiters have semi-random parameters (such as the occurrence and number of light masts; rings around planets; bridges in cities), and their initial value is taken from this seed.

 

There are a lot more parameters per stellar object (be it star, planet, moon, orbiter, or city), and all these values are filled in with sensible values by the complicated routines which create stellar systems, and they always seem to generate a believable system. Well it IS one of the things I've found out, but it's too damn late in the evening to start writing that.

<< Previous :: Next >>

[Jongware]

Based on original data and algorithms from Frontier:Elite 2 and Frontier:First Encounters by David Braben (Frontier Developments)

Original copyright holders:
Elite 4: The Next Encounter © David Braben 2011?
First Encounters © David Braben 1995
Frontier © David Braben 1993
Elite © David Braben and Ian Bell 1984

 

For any real questions -- I will not provide the complete source code! -- you can drop me a mail at jongware.