![]() |
| Most recent update (All By Hand(TM)): 1-Apr-2006 01:04 |
|
Here we are: Born to be kings,
The Frontier Galaxy II: Distant SunsThe 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 MineThere 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:
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 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 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 MineIf 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: 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: Not quite sure. Used in the 'smuggling' scenario, hence the name. Government_Allegiance & 0x3f: one of the following strings: (Government_Allegiance >> 6) & 7: one of the following strings: 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". 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: LongDesc: subtract 0x8000, then one of the following strings:
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 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 MineOnly 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 MineThere 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.
Based on original data and algorithms from Frontier:Elite 2 and Frontier:First Encounters by David Braben (Frontier Developments) Original copyright holders: | ||||||||||||||||||||||||||||||||
![]() |
For any real questions -- I will not provide the complete source code! -- you can drop me a mail at jongware. |