![]() |
| Most recent update (All By Hand(TM)): 1-Apr-2006 01:04 |
|
As the world turns, I spread like germs
The Frontier Galaxy V: A Planet By Any Other NameThe first part in this series showed how to create millions upon millions of stars and how to label each and every one of them, albeit with a rather limited routine which could only produce some 32,768 different names. In Part II the trick to name individual stars was revealed: look'em up in a big table. Want more names, expand this table. In the previous part you could trace how the designations of individual planets and moons were constructed, leading to unimaginative names such as "Laaycan E11a" (-73,243). However, as soon as a star gets incorporated into the human sphere of influence, the first thing the intrepid explorer does is to dispatch a high speed courier to the Galactic Planet/Star Database office, registering the claimed planets under a name of his choice. In the part of space colonized by humans we find individual worlds called "Williams's Legacy" (Miquve (-13,1)), "Ashfield Hollow" (Liaqulia (11,8)) and "New California" (Zevear (4,14)) (some unlucky explorers are commemorated with names such as "Du Prés's Grave" -- well, at least he's got his name into the history books). After a couple of years the population concentrates in dwellings large enough to build starports, and so appear on the galactic map. The richest colonies may even construct orbiters (usually named after the big shot who provided the cash: "Donaldson Orbiter", Andackio (-9,1)).
In Part III you could see where the crucial decision is taken to honor a planet with a name, and how it is determined how many towns and orbiters there should be; each one gets its name from the routine void GenerateName (Planet_t *planet, int Counter, int NameType, int argC) { GSystem_namedobjects++; planet[Counter].level |= 0x80; if (BasePlayerVariables_government_allegiance == 3) // Alliance { if (NameType == NAMETYPE_PROJECT || NameType == NAMETYPE_COLONY) { Get_any_Name (NAMETYPE_WORLDNAME2, argC, planet[Counter].random_seed, planet[Counter].name); return; } if (NameType == NAMETYPE_CITYNAME || NameType == NAMETYPE_ORBITERNAME) { Get_any_Name (NAMETYPE_WORLDNAME3, argC, planet[Counter].random_seed, planet[Counter].name); return; } } Get_any_Name (NameType, argC, planet[Counter].random_seed, planet[Counter].name); } Every call to #define NAMETYPE_MALEFULLNAME 1 #define NAMETYPE_FEMALEFULLNAME 2 #define NAMETYPE_ANYFULLNAME 3 #define NAMETYPE_CITYNAME 6 #define NAMETYPE_ORBITERNAME 7 #define NAMETYPE_PROJECT 8 #define NAMETYPE_COLONY 9 #define NAMETYPE_WORLD 10 #define NAMETYPE_INTREPID 11 #define NAMETYPE_INDUSTRY 12 #define NAMETYPE_WORLDNAME2 16 // "{16}'s End" etc. #define NAMETYPE_WORLDNAME3 17 // "New {16}" etc. #define NAMETYPE_SHIPNAME_AA000 18 #define NAMETYPE_SHIPNAME_000A 19 #define NAMETYPE_SHIPNAME_AA0 20 In the code shown so far not every type of name gets used; The code for Note also that an object-with-a-name (be it planet, city or orbiter) gets a bit set -- probably useful for some shortcut elsewhere in the game.
The array with all the names can be downloaded here. unsigned int name_getrandom (int *shuffle0, int *shuffle1, unsigned int max_value) { (*shuffle0) += (*shuffle1); (*shuffle1) = _lrotr (*shuffle1, 27); (*shuffle0) += (*shuffle1); (*shuffle0) = _lrotr (*shuffle0, 16); return ((((*shuffle0) & 0xffff)*max_value) >> 16) & 0xffff; } void Get_any_Name (int NameType, int /* ?? */, int code, char *dest) { int l_newcode; char buf[32], *ptr; l_newcode = _lrotl(code, 16); code += l_newcode; l_newcode = _lrotr(l_newcode, 25); code += l_newcode; l_newcode = _lrotr(l_newcode, 28); code += l_newcode; if (NameType == NAMETYPE_WORLDNAME2 || NameType == NAMETYPE_WORLDNAME3) { strcpy (buf, Names[name_getrandom(&code,&l_newcode,88)+394]); } else { if ((code & 0xff) < 25) { strcpy (buf, Names[name_getrandom(&code,&l_newcode,10)+79]); strcat (buf, "s"); if (!(code & 0x800)) strcat (buf, "on"); } else strcpy (buf, Names[name_getrandom(&code,&l_newcode,138)+89]); } switch (NameType) { case 6: strcpy (dest, Names[name_getrandom(&code,&l_newcode,19)+284]); break; case 7: strcpy (dest, Names[name_getrandom(&code,&l_newcode,11)+297]); break; case 8: strcpy (dest, Names[name_getrandom(&code,&l_newcode,24)+308]); break; case 9: strcpy (dest, Names[name_getrandom(&code,&l_newcode,34)+313]); break; case 10: strcpy (dest, Names[name_getrandom(&code,&l_newcode,16)+342]); break; case 11: strcpy (dest, Names[name_getrandom(&code,&l_newcode,19)+358]); break; case 12: strcpy (dest, Names[name_getrandom(&code,&l_newcode, 7)+377]); break; case 13: strcpy (dest, Names[name_getrandom(&code,&l_newcode, 9)+384]); break; case 14: strcpy (dest, Names[name_getrandom(&code,&l_newcode, 1)+393]); break; // "Police"! case 15: strcpy (dest, Names[name_getrandom(&code,&l_newcode,88)+394]); break; case 16: strcpy (dest, Names[name_getrandom(&code,&l_newcode,11)+482]); break; case 17: strcpy (dest, Names[name_getrandom(&code,&l_newcode,17)+493]); break; default: strcpy (dest, "UNDEFINED"); // Never saw this one appear, but what the hell } ptr = strchr (dest, 0xff); if (ptr) { memmove (ptr+strlen(buf), ptr+3, strlen(ptr)-2); memcpy (ptr, buf, strlen(buf)); } } In The function Some names are not merely copied from the list: a few first names can act as surname with the addition of "s" or "son". The In the Return to the EarthThe name routine can create lots of Havens and Heavens (and the odd Wreck or Grave), but the familiar Venus, Jupiter and Pluto are missing, and if you know your surroundings, so are Merlin and Waypoint. As outlined in Planet_t ManufacturedSystem[147]; The hardcoded planets still need a random seed, since this is used for the layout of cities, the number of rings around planets, and some more items. Jotting down random numbers is a boring job, and one the computer can fully do on its own. (Wherever a specific seed is wanted it is supplied; if it's a zero, a real random is created. Why would one want a specific random number? Well, in the case of New San Francisco, we don't want any random city, it has to be the one with the large bridge. And Jupiter needs a few thin rings, where Saturn wants them big. Probably Dave just generated cities and planets until he found the ones he liked, and copied that random number.) Two other helper functions are also introduced. Given a (long!) list of parameters, these are stored in the appropriate places of the Planets array. Some of the parameters are also recalculated, presumably from a sensible unit into binary notation. See, for example, the expansion of "normal" longitude and latitude values into word values, and how the temperature apparently is input in Celsius but gets converted to Kelvin. unsigned int SolarSystem_random = 0x1234; unsigned int SolarSystem_seed = 0x5678; void HandcodedRandomizer (void) { SolarSystem_random = ((SolarSystem_random * 3179)/39) & 0xffff; SolarSystem_seed = ((SolarSystem_seed * 3137)/39) & 0xffff; } void CreateSolarSystem_Body (Planet_t *dest,int mass,unsigned int random_seed,short eccentricity, int inclination,int orbits_around,int distance,int declination,short surfaceTemp,char Char_24, int Dword_28,short description,short ObjectNumber,char *name) { dest->mass = mass+1; if (random_seed) { dest->random_seed = (random_seed<<16) | (random_seed>>16); } else { dest->random_seed = (SolarSystem_random << 16) + (SolarSystem_seed & 0xffff); HandcodedRandomizer(); } dest->parent = orbits_around; dest->descriptioncode = description; dest->model = ObjectNumber; dest->orbital_radius = distance; dest->latitude = (declination<<16)/360; dest->orbital_period = 0; dest->tempptr = 0; dest->eccentricity = eccentricity; dest->longitude = (inclination<<16)/3600; dest->temperature = surfaceTemp+273; strcpy (dest->name, name); dest->field_3A = 0; dest->field_3C = 0; dest->rotspeed = Char_24; dest->level = (orbits_around >= 2) ? 2 : orbits_around; dest->field_40 = 0; dest->field_42 = (Dword_28<<16)/360; dest->field_42 = 0; } void CreateSolarSystem_City (Planet_t *dest,int random_seed,int lati,int longi,short on_body, short ObjectNumber,char *name) { dest->mass = 0x0FFF60000; if (random_seed) { dest->random_seed = random_seed; } else { dest->random_seed = (SolarSystem_random << 16) + (SolarSystem_seed & 0xffff); HandcodedRandomizer(); } dest->parent = on_body; dest->descriptioncode = 35; dest->model = ObjectNumber; dest->orbital_radius = 0; dest->latitude = -((lati<<16)/36000)-0x4000; dest->orbital_period = 0; dest->tempptr = 0; dest->eccentricity = 0; dest->longitude = (longi<<16)/36000; dest->temperature = 293; strcpy (dest->name, name); dest->field_3A = 0; dest->field_3C = 0; dest->rotspeed = 0; dest->level = 3; dest->field_40 = 0; dest->field_42 = 0; } The entire list of manufactured systems has 147 elements. The first element of each distinct system is found in a list, and the list for this system stops when the void CreateHandcodedSystems (void) { CreateSolarSystem_Body(&ManufacturedSystem[0], 200000000, 0, 0, 0, 0, 0, 0, 5800, 2, 0, 22, 141, "Sol"); CreateSolarSystem_Body(&ManufacturedSystem[1], 33, 0, 206, 70, 1, 1725554, 30, 350, 0, 0, 3, 120, "Mercury"); CreateSolarSystem_Body(&ManufacturedSystem[2], 0, 0, 0, 900, 2, 220, 50, 15, 12, 0, 32, 72, "Daedalus"); CreateSolarSystem_Body(&ManufacturedSystem[3], 487, 0, 1, 34, 1, 3224611, 220, 480, 0, 0, 12, 123, "Venus"); CreateSolarSystem_Body(&ManufacturedSystem[4], 598, 0x12340ABC, 17, 0, 1, 4458427, 90, 22, 1, 23, 10, 129, "Earth"); CreateSolarSystem_City(&ManufacturedSystem[5], 0, -0x3370, 0x0B34, 5, 84, "London"); CreateSolarSystem_City(&ManufacturedSystem[6], 0, -14415, 1985, 5, 83, "Paris"); CreateSolarSystem_City(&ManufacturedSystem[7], 0, -31505, 2390, 5, 90, "Tokyo"); CreateSolarSystem_City(&ManufacturedSystem[8], 0, 0x0FFFF5E59, 0x285, 5, 84, "New York"); CreateSolarSystem_City(&ManufacturedSystem[9], 0, 0x0FFFFB738, 0x0FCC, 5, 84, "New Moscow"); CreateSolarSystem_City(&ManufacturedSystem[10], 0, 0x0FFFF6124, 0x0FFFFEFEC, 5, 90, "New San Francisco"); CreateSolarSystem_City(&ManufacturedSystem[11], 0, 0x0FFFF94A5, 0x0FFFFF636, 5, 0x5A, "Sydney"); CreateSolarSystem_Body(&ManufacturedSystem[12], 0, 0, 0, 0x0EB, 5, 1257, 0x78, 15, 0x0A, 0, 34, 80, "Abraham Lincoln"); CreateSolarSystem_Body(&ManufacturedSystem[13], 0, 0, 0, 235, 5, 1257, 240, 15, 10, 0, 34, 80, "M.Gorbachev"); CreateSolarSystem_Body(&ManufacturedSystem[14], 0, 0, 0, 235, 5, 1257, 0, 15, 10, 0, 34, 80, "Li Qing Jao"); CreateSolarSystem_Body(&ManufacturedSystem[15], 7, 4660, 54, 51, 5, 11456, 150, -20, 0, 0, 3, 120, "Moon"); CreateSolarSystem_City(&ManufacturedSystem[16], 0, -17127, 871, 16, 96, "Apollonius City"); CreateSolarSystem_Body(&ManufacturedSystem[17], 0, 0, 0, 0x384, 16, 250, 0, 15, 11, 0, 33, 73, "Galileo"); CreateSolarSystem_Body(&ManufacturedSystem[18], 64, 3168665610, 93, 19, 1, 6791949, 80, 15, 1, 24, 9, 125, "Mars"); CreateSolarSystem_City(&ManufacturedSystem[19], 0x0FBFEFF0, 0x0FFFF84EF, 0x956, 0x13, 0x54, "Olympus Village"); CreateSolarSystem_City(&ManufacturedSystem[20], 0x0E1234567, 0x0FFFFCC90, 0x0B34, 0x13, 0x53, "Quenisset"); CreateSolarSystem_Body(&ManufacturedSystem[21], 0, 0, 0, 900, 19, 180, 0, 0x0F, 0x0A, 0, 34, 80, "Mars High"); CreateSolarSystem_Body(&ManufacturedSystem[22], 0, 0x0EF123, 0x15, 0x0B, 0x13, 0x117, 0, 0x0FFFFFFBE, 5, 0, 1, 112, "Phobos"); CreateSolarSystem_Body(&ManufacturedSystem[23], 0, 0x56789, 3, 0x12, 0x13, 0x2BC, 0, -66, 4, 0, 1, 112, "Deimos"); CreateSolarSystem_Body(&ManufacturedSystem[24], 1, 0x0EF123, 0x4F, 0x6A, 1, 0x0BABE2E, 0x0C8, -120, 0, 0, 2, 119, "Ceres"); CreateSolarSystem_Body(&ManufacturedSystem[25], 189900, 1610617396, 49, 13, 1, 23195147, 300, -150, 2, 3, 15, 134, "Jupiter"); CreateSolarSystem_Body(&ManufacturedSystem[26], 0, 0, 3, 36, 26, 5394, 0x0AA, 0x0FFFFFF65, 2, 0, 1, 112, "Amalthea"); CreateSolarSystem_Body(&ManufacturedSystem[27], 9, 0, 4, 31, 26, 0x3121, 0x50, 0x0FFFFFF6F, 0, 0, 5, 122, "Io"); CreateSolarSystem_Body(&ManufacturedSystem[28], 0, 0, 0, 0x384, 28, 0x8C, 0x5A, 0x0F, 0x0B, 0, 33, 73, "Columbus"); CreateSolarSystem_Body(&ManufacturedSystem[29], 5, 0, 9, 36, 26, 20000, 270, -159, 0, 0, 2, 119, "Europa"); CreateSolarSystem_Body(&ManufacturedSystem[30], 0x0F, 214375, 2, 33, 26, 31888, 120, -160, 0, 0, 3, 120, "Ganymede"); CreateSolarSystem_Body(&ManufacturedSystem[31], 10, 74565, 7, 0x24, 26, 56028, 10, -160, 0, 0, 3, 120, "Callisto"); CreateSolarSystem_Body(&ManufacturedSystem[32], 56860, 0x0FFA10123, 55, 25, 1, 42527914, 220, -180, 2, 0x1D, 14, 134, "Saturn"); CreateSolarSystem_Body(&ManufacturedSystem[33], 1, 0, 0x14, 0, 33, 0x15A7, 0x0FA, -190, 2, 0, 2, 119, "Mimas"); CreateSolarSystem_Body(&ManufacturedSystem[34], 1, 0, 4, 0, 33, 0x1BB4, 0x28, -190, 0, 0x32, 2, 119, "Enceladus"); CreateSolarSystem_Body(&ManufacturedSystem[35], 1, 0, 0, 0, 33, 0x2258, 0x5A, 0x0FFFFFF42, 0, 0, 2, 119, "Tethys"); CreateSolarSystem_Body(&ManufacturedSystem[36], 1, 0, 2, 0, 33, 0x2BE3, 0x8C, 0x0FFFFFF42, 0, 0x1E, 2, 119, "Dione"); CreateSolarSystem_Body(&ManufacturedSystem[37], 1, 0, 1, 0, 33, 0x3D59, 0x154, 0x0FFFFFF42, 0, 0x5A, 2, 119, "Rhea"); CreateSolarSystem_Body(&ManufacturedSystem[38], 14, 0, 0x1D, 0, 33, 0x8E42, 0x0C8, 0x0FFFFFF58, 0, 0, 7, 124, "Titan"); CreateSolarSystem_Body(&ManufacturedSystem[39], 0, 0, 0, 0x384, 39, 0x1F4, 0x46, 0x0F, 0x0B, 0, 33, 73, "Titan City"); CreateSolarSystem_Body(&ManufacturedSystem[40], 0, 0, 0x68, 0x126, 0x21, 0x0AC69, 0x50, 0x0FFFFFF41, 0, 0, 1, 117, "Hyperion"); CreateSolarSystem_Body(&ManufacturedSystem[41], 1, 0, 0x1C, 0x6E, 0x21, 0x19E8E, 0x78, 0x0FFFFFF41, 0, 0, 2, 119, "Iapetus"); CreateSolarSystem_Body(&ManufacturedSystem[42], 8660, 0x7F801234, 0x2F, 8, 1, 85520744, 0x46, -210, 2, 98, 13, 135, "Uranus"); CreateSolarSystem_Body(&ManufacturedSystem[43], 0, 0, 0x11, 0x3D4, 0x2B, 0x0F22, 0x122, 0x0FFFFFF29, 0, 0, 1, 0x75, "Miranda"); CreateSolarSystem_Body(&ManufacturedSystem[44], 1, 0, 3, 0x3D4, 0x2B, 0x165A, 0x28, 0x0FFFFFF29, 0, 0x5A, 2, 0x77, "Ariel"); CreateSolarSystem_Body(&ManufacturedSystem[45], 1, 0, 4, 0x3D4, 0x2B, 0x1F15, 0x64, 0x0FFFFFF29, 0, 0x1E, 2, 0x77, "Umbriel"); CreateSolarSystem_Body(&ManufacturedSystem[46], 1, 0, 2, 0x3D4, 0x2B, 0x32FD, 0x96, 0x0FFFFFF29, 0, 0x46, 2, 0x77, "Titania"); CreateSolarSystem_Body(&ManufacturedSystem[47], 1, 0, 1, 0x3D4, 0x2B, 0x4438, 0x14, 0x0FFFFFF29, 0, 0x0A, 2, 119, "Oberon"); CreateSolarSystem_Body(&ManufacturedSystem[48], 10300, 0x7D40789A, 9, 0x12, 1, 0x7FCD123, 0x96, 0x0FFFFFF24, 2, 0, 13, 135, "Neptune"); CreateSolarSystem_Body(&ManufacturedSystem[49], 6, 0x23456, 0, 0x63F, 0x31, 0x2953, 0x136, 0x0FFFFFF42, 0, 0, 4, 121, "Triton"); CreateSolarSystem_Body(&ManufacturedSystem[50], 0, 0, 0x2ED, 0x110, 0x31, 0x28780, 0x3C, 0x0FFFFFF1E, 0, 0, 1, 117, "Nereid"); CreateSolarSystem_Body(&ManufacturedSystem[51], 1, 0, 250, 172, 1, 175833702, 170, -232, 0, 0, 2, 119, "Pluto"); CreateSolarSystem_Body(&ManufacturedSystem[52], 1, 0, 0, 0x28A, 0x34, 566, 0x14, 0x0FFFFFF18, 0, 0, 2, 119, "Charon"); ManufacturedSystem[53].mass = 0; ManufacturedSystem[54].mass = 0; ManufacturedSystem[55].mass = 0; CreateSolarSystem_Body(&ManufacturedSystem[56], 398000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, "Alpha Centauri A,B"); CreateSolarSystem_Body(&ManufacturedSystem[57], 220000000, 0, 0, 0, 1, 52029761, 0, 5900, 0, 0, 22, 141, "Alpha Centauri A"); CreateSolarSystem_Body(&ManufacturedSystem[58], 178000000, 0, 0, 0, 1, 52029761, 180, 5000, 0, 0, 21, 140, "Alpha Centauri B"); CreateSolarSystem_Body(&ManufacturedSystem[59], 180000, 0x0FFFFFFFF, 3, 2, 1, 0x633D282, 0x5A, 0x0FFFFFF30, 1, 80, 15, 134, "Lagrange"); CreateSolarSystem_Body(&ManufacturedSystem[60], 6, 0, 3, 0x33A, 4, 0x4E20, 0, 0x0FFFFFF27, 0, 0, 2, 0x77, "2042 L1"); CreateSolarSystem_Body(&ManufacturedSystem[61], 10000, 0, 0x57, 0x7D, 1, 0x35A4E900, 0, 0x0FFFFFF0B, 0, 0x0AF, 13, 135, "2071 AC3"); CreateSolarSystem_Body(&ManufacturedSystem[62], 1, 0, 0x0B2, 0x2DA, 6, 0x1E2A, 0, 0x0FFFFFF03, 0, 0, 2, 119, "2075 AC3a"); CreateSolarSystem_Body(&ManufacturedSystem[63], 20000000, 0, 450, 800, 1, 0x0FFFFFFFF, 0, 0x0CE4, 2, 75, 18, 138, "Proxima Centauri"); CreateSolarSystem_Body(&ManufacturedSystem[64], 456, 0, 10, 772, 8, 400000, 0, 3, 2, 60, 8, 0x80, "Eden"); CreateSolarSystem_Body(&ManufacturedSystem[65], 0, 0, 0, 0, 9, 300, 0, 15, 12, 0, 32, 72, "Eden Station"); CreateSolarSystem_Body(&ManufacturedSystem[66], 6, 0, 350, 758, 8, 1000000, 0, -81, 1, 170, 2, 119, "2045 PC2"); ManufacturedSystem[67].mass = 0; CreateSolarSystem_Body(&ManufacturedSystem[68], 658000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, "Sirius, Sirius B"); CreateSolarSystem_Body(&ManufacturedSystem[69], 462000000, 0, 0, 0, 1, 0x2B01FD6, 0, 0x2328, 2, 0, 24, 143, "Sirius"); CreateSolarSystem_Body(&ManufacturedSystem[70], 196000000, 0, 0, 0, 1, 0x2B01FD6, 0x0B4, 0x2AF8, 0x0D, 0, 25, 148, "Sirius B"); CreateSolarSystem_Body(&ManufacturedSystem[71], 0x23, 0, 0x0E, 0x186, 3, 0x366C9, 0, 0x9A, 5, 0x78, 5, 122, "Lucifer"); CreateSolarSystem_City(&ManufacturedSystem[72], 0, 0x0FFFFAD36, 0x6F8, 4, 96, "Factory Central"); CreateSolarSystem_Body(&ManufacturedSystem[73], 210000, 0, 0x11B, 0x147, 1, 0x5D0291AA, 0, 0x0FFFFFF06, 0, 0x5F, 15, 134, "Waypoint"); ManufacturedSystem[74].mass = 0; CreateSolarSystem_Body(&ManufacturedSystem[75], 172000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, "Wolf 630 A,B"); CreateSolarSystem_Body(&ManufacturedSystem[76], 91200000, 0, 0, 0x3B6, 1, 0x1FE39C6, 0, 0x0D48, 1, 0, 20, 138, "Wolf 630 A"); CreateSolarSystem_Body(&ManufacturedSystem[77], 80800000, 0, 0, 0x3B6, 1, 0x1FE39C6, 0x0B4, 0x0D16, 1, 0, 20, 138, "Wolf 630 B"); CreateSolarSystem_Body(&ManufacturedSystem[78], 150500000, 1916032639, 0, 0, 1, 773532400, 0x64, 10700, 0x0C, 0, 25, 148, "Van Biesbroeck 8"); CreateSolarSystem_Body(&ManufacturedSystem[79], 980000, 0x0FEDCBA98, 0x5A, 0x4B0, 4, 0x1000AE0, 0, 0x4B0, 3, 0x0A, 0x11, 0x89, "McCarthy"); CreateSolarSystem_Body(&ManufacturedSystem[80], 620, 0x54321, 0x0E, 0x186, 5, 0x143E9, 0, 0x18, 3, 0x8C, 0x0A, 0x7E, "Landfall"); CreateSolarSystem_City(&ManufacturedSystem[81], 0, 0x0FFFFAD36, 0x6F8, 6, 0x53, "Mayflower City"); CreateSolarSystem_Body(&ManufacturedSystem[82], 0, 0, 0, 0, 6, 0x1F4, 0, 0x0F, 0x0B, 0, 0x21, 0x49, "Mayflower High"); CreateSolarSystem_Body(&ManufacturedSystem[83], 658000000, 0, 0, 0x454, 1, 0x0FFFFFFFF, 0x104, 0, 0, 0, 0, 0x17, "Wolf 629 A,B"); CreateSolarSystem_Body(&ManufacturedSystem[84], 41500000, 0, 0, 0x0FFFFFB7F, 9, 0x2C3835, 0, 0x0C80, 1, 0, 0x14, 0x8A, "Wolf 629 A"); CreateSolarSystem_Body(&ManufacturedSystem[85], 41000000, 0, 0, 0x0FFFFFB7F, 9, 0x2C3835, 0x0B4, 0x0C4E, 1, 0, 0x14, 0x8A, "Wolf 629 B"); ManufacturedSystem[86].mass = 0; CreateSolarSystem_Body(&ManufacturedSystem[87], 218000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x17, "61 Cygni A,B"); CreateSolarSystem_Body(&ManufacturedSystem[88], 118000000, 0, 0, 0, 1, 0x0A4A7414, 0, 0x1388, 1, 0, 0x15, 0x8C, "61 Cygni A"); CreateSolarSystem_Body(&ManufacturedSystem[89], 100000000, 0, 0, 0, 1, 0x0A4A7414, 0x0B4, 0x1324, 1, 0, 0x15, 0x8C, "61 Cygni B"); CreateSolarSystem_Body(&ManufacturedSystem[90], 630, 0, 0x53, 0x0E4, 3, 0x227673, 0, 0x0FFFFFFFB, 2, 0, 0x0B, 0x7F, "Scott"); CreateSolarSystem_City(&ManufacturedSystem[91], 0, 0x0FFFFAD36, 0x6F8, 4, 0x55, "Amundsen"); CreateSolarSystem_Body(&ManufacturedSystem[92], 430000, 0, 0x11B, 0x27A, 1, 0x75357C1A, 0, 0x0FFFFFF06, 0, 0, 0, 0x17, "61 Cygni A,B 1,2"); CreateSolarSystem_Body(&ManufacturedSystem[93], 230000, 0, 0, 0x645, 6, 0x340B08, 0, 0x0FFFFFEFC, 1, 0, 0x0F, 0x86, "61 Cygni A,B 1"); CreateSolarSystem_Body(&ManufacturedSystem[94], 200000, 0, 0, 0x645, 6, 0x340B08, 0x0B4, 0x0FFFFFEFC, 1, 0, 0x0F, 0x86, "61 Cygni A,B 2"); CreateSolarSystem_Body(&ManufacturedSystem[95], 35, 0, 0x54, 0x64C, 8, 0x2EE0, 0, 0x0FFFFFF2B, 2, 0, 5, 0x7A, "61 Cygni A,B 2a"); CreateSolarSystem_Body(&ManufacturedSystem[96], 3, 0, 0x5C, 0x6C0, 6, 0x1D46348, 0, 0x0FFFFFEF2, 1, 0, 2, 0x77, "61 Cygni A,B 1,2a"); ManufacturedSystem[97].mass = 0; CreateSolarSystem_Body(&ManufacturedSystem[98], 201500000, 0, 0, 0, 0, 0, 0, 0x170C, 2, 0, 0x16, 0x8D, "Eta Cassiopeia"); CreateSolarSystem_Body(&ManufacturedSystem[99], 38, 0, 0x102, 0x33E, 1, 0x0FCD22, 0, 0x1CC, 0, 0, 3, 0x78, "Rock"); CreateSolarSystem_Body(&ManufacturedSystem[100], 504000, 0x0CF019875, 0, 0x0A, 1, 0x503CBB, 0, 0x0E, 1, 0x28, 0x10, 0x88, "Between"); CreateSolarSystem_Body(&ManufacturedSystem[101], 64, 0x12ABCFE, 0x68, 0x12, 3, 0x0CAED, 0, 0x0F, 1, 0x18, 9, 0x7D, "Navy Central"); CreateSolarSystem_Body(&ManufacturedSystem[102], 0, 0, 0, 0x72, 4, 0x0B4, 0, 0x0F, 0x0A, 0, 0x22, 0x50, "Morgue's Mortuary"); CreateSolarSystem_Body(&ManufacturedSystem[103], 610, 0x7834536, 0, 0x0A, 1, 0x503CBB, 0x12C, 0x18, 1, 0x14, 0x0A, 0x7E, "Trojan"); CreateSolarSystem_City(&ManufacturedSystem[104], 0, 0x0FFFFCC90, 0x0B34, 6, 0x54, "New Kyoto"); CreateSolarSystem_City(&ManufacturedSystem[105], 0, 0x0FFFFAD36, 0x6F8, 6, 0x53, "Sunnyville"); CreateSolarSystem_City(&ManufacturedSystem[106], 0, 0x0FFFF9F83, 0x0FAC, 6, 0x53, "Venice on Land"); CreateSolarSystem_City(&ManufacturedSystem[107], 0, 0x0FFFF5E59, 0x285, 6, 0x52, "Manchester"); CreateSolarSystem_City(&ManufacturedSystem[108], 0, 0x0FFFFB739, 0x0FCC, 6, 0x51, "Epping Newtown"); CreateSolarSystem_Body(&ManufacturedSystem[109], 0, 0, 0, 0x44C, 6, 0x274, 0x78, 0x0F, 0x0A, 0, 0x22, 0x50, "J.F.Kennedy"); CreateSolarSystem_Body(&ManufacturedSystem[110], 5, 0x124534, 0x36, 0x33, 6, 0x0D80, 0, 0x0FFFFFFEC, 0, 0, 2, 0x77, "New Moon"); CreateSolarSystem_Body(&ManufacturedSystem[111], 505, 0x1CFD75F, 0, 0x0A, 1, 0x503CBB, 0x3C, 0x0A, 1, 0x0A0, 0x0A, 0x7E, "Feynman"); CreateSolarSystem_City(&ManufacturedSystem[112], 0, 0x0FFFFC7B1, 0x7C1, 0x0E, 0x54, "Naunton Estates"); CreateSolarSystem_City(&ManufacturedSystem[113], 0, 0x0FFFF9F83, 0x0FAC, 0x0E, 0x53, "Tarbit's Landing"); CreateSolarSystem_Body(&ManufacturedSystem[114], 0, 0, 0, 0x9C4, 0x0E, 0x274, 0x78, 0x0F, 0x0B, 0, 0x21, 0x49, "Angus Manwaring"); CreateSolarSystem_Body(&ManufacturedSystem[115], 19000000, 0, 0x2D, 0x32, 1, 0x104FAB10, 0x0C8, 0x0C80, 2, 0x4B, 0x14, 0x8A, "Eta Cassiopeia B"); CreateSolarSystem_Body(&ManufacturedSystem[116], 9, 0, 350, 758, 0x12, 0x0F4240, 0, 0x0FFFFFFAF, 1, 0x0AA, 3, 0x78, "Firing Range"); CreateSolarSystem_Body(&ManufacturedSystem[117], 9000, 0x7F801234, 0x37, 0x0A, 1, 0x389A6E97, 0, 0x0FFFFFF07, 2, 0x9E, 0x0D, 0x87, "Eta Cassiopeia 5"); ManufacturedSystem[118].mass = 0; CreateSolarSystem_Body(&ManufacturedSystem[119], 19500000, 0, 0x1C2, 0x320, 0, 0, 0, 0x0C80, 0, 0x4B, 0x12, 0x8A, "Ross 154"); CreateSolarSystem_Body(&ManufacturedSystem[120], 40, 0, 9, 0x24, 1, 0x6CD92, 0, 0x0FFFFFFCD, 0, 0, 2, 0x77, "Dust Ball"); CreateSolarSystem_Body(&ManufacturedSystem[121], 65600, 0x8D4078FF, 9, 0x1C, 1, 0x16AD3E, 0x9B, 0x0FFFFFFEC, 3, 0, 0x0D, 0x87, "Aster"); CreateSolarSystem_Body(&ManufacturedSystem[122], 25, 0, 26, 300, 3, 6727, 145, -4, 1, 0x3C, 0x0A, 0x7F, "Merlin"); CreateSolarSystem_City(&ManufacturedSystem[123], 0, 0x2145, 0x82D6, 4, 0x55, "Sirocco Station"); CreateSolarSystem_Body(&ManufacturedSystem[124], 7, 0, 26, 190, 3, 8087, 0, -40, 1, 0x3C, 3, 0x78, "Willow"); CreateSolarSystem_Body(&ManufacturedSystem[125], 29, 0, 146, 53, 1, 13063112, 0, -185, 1, 10, 3, 120, "Ross 154 3"); ManufacturedSystem[126].mass = 0; CreateSolarSystem_Body(&ManufacturedSystem[127], 118000000, 0, 0, 0, 0, 0, 0, 0x1388, 0, 0, 0x15, 0x8C, "Lave"); CreateSolarSystem_Body(&ManufacturedSystem[128], 598, 19666997, 0x26, 0, 1, 0x2275FB, 0, 0x0E, 1, 0, 0x0A, 0x7E, "Planet Lave"); CreateSolarSystem_Body(&ManufacturedSystem[129], 0, 0, 0, 0x9C4, 2, 0x274, 0x78, 0x0F, 0x0C, 0, 0x20, 0x48, "Lave Station"); ManufacturedSystem[130].mass = 0; CreateSolarSystem_Body(&ManufacturedSystem[131], 200000000, 0, 0, 0, 0, 0, 0, 0x1388, 0, 0, 0x16, 0x8D, "Diso"); CreateSolarSystem_Body(&ManufacturedSystem[132], 598, 0x12C1835, 0x26, 0, 1, 0x489B9B, 0, 0x0FFFFFFE8, 1, 0x1E, 0x0A, 0x7F, "Birmingham"); CreateSolarSystem_Body(&ManufacturedSystem[133], 0, 0, 0, 0x9C4, 2, 0x274, 0x78, 0x0F, 0x0C, 0, 0x20, 0x48, "Shifnalport"); ManufacturedSystem[134].mass = 0; CreateSolarSystem_Body(&ManufacturedSystem[135], 20000000, 0, 0, 0, 0, 0, 0, 0x1388, 0, 0, 0x14, 0x8A, "Leesti"); CreateSolarSystem_Body(&ManufacturedSystem[136], 598, 19666997, 0x26, 0, 1, 0x17C79B, 0, 0x10, 1, 0x1E, 3, 0x78, "Leesti 1"); CreateSolarSystem_Body(&ManufacturedSystem[137], 0, 0, 0, 0x9C4, 2, 0x274, 0x78, 0x0F, 0x0C, 0, 0x20, 0x48, "George Lucas"); ManufacturedSystem[138].mass = 0; CreateSolarSystem_Body(&ManufacturedSystem[139], 20000000, 0, 0, 0, 0, 0, 0, 5000, 0, 0, 23, 142, "Zaonce"); CreateSolarSystem_Body(&ManufacturedSystem[140], 598, 19666997, 0x26, 0, 1, 1558427, 0, 0x10, 1, 30, 3, 120, "Industry"); CreateSolarSystem_Body(&ManufacturedSystem[141], 0, 0, 0, 2500, 2, 628, 120, 15, 12, 0, 32, 72, "Ridley Scott"); ManufacturedSystem[142].mass = 0; CreateSolarSystem_Body(&ManufacturedSystem[143], 200000000, 0, 0, 0, 0, 0, 0, 5000, 0, 0, 22, 141, "Riedquat"); CreateSolarSystem_Body(&ManufacturedSystem[144], 598, 0x12C1835, 0x26, 0, 1, 0x2275FB, 0, 0x1D, 1, 0x1E, 0x0A, 0x7E, "Waterloo"); CreateSolarSystem_Body(&ManufacturedSystem[145], 0, 0, 0, 0x9C4, 2, 0x274, 0x78, 0x0F, 0x0B, 0, 33, 0x49, "La Soeur du Dan Ham"); ManufacturedSystem[146].mass = 0; } We need a way of finding the correct system when its seed is zero. That's done by looping through the following array, checking your system's UniqueId against the first value; the second value is the index into the dd offsets_of_handcoded_systems[][2] =
{
0x2A49718, 0, // Sol
0x6A49718, 56, // Alpha Centauri
0xEA47716, 75, // Wolf 630
0x2A4B717, 87, // 61 Cygni
0x2A49719, 68, // Sirius
0x6A4D718, 98, // Eta Cassiopeia
0x6A49717, 119, // Ross 154
0x2A3D715, 127, // Lave
0x6A3D715, 131, // Diso
0xEA3D715, 135, // Leesti
0x2A3D716, 139, // Zaonce
0, 0
};
Thoroughly creepy is that Riedquat is not in this list! As you can see when searching for the correct system, the search stops when it encounters a zero for map coordinate, and starts copying data from whereever it was at that moment. That's why the pointer to data-to-be-copied is initialized with the objects for Riedquat...
The routine Copying (and adjusting the odd parameter) is done in if (gensysparam->seed == 0)
{
// This is a handcoded system
i = 0;
// Code to copy lots and lots of data omitted...
planets[i].mass = 0;
return i;
}
Replace these lines with the following snippet of code. if (gensysparam->seed == 0)
{
// This is a handcoded system
Planet_t *manufactured = &ManufacturedSystem[143];
i = 0;
while (offsets_of_handcoded_systems[i][0])
{
if (offsets_of_handcoded_systems[i][0] == gensysparam->mapcoordinate)
{
manufactured = &ManufacturedSystem[offsets_of_handcoded_systems[i][1]];
break;
}
i++;
}
i = 0;
while (manufactured[i].mass)
{
if (manufactured[i].descriptioncode == 35)
{
memcpy (&planets[i], &manufactured[i], sizeof(Planet_t));
GSystem_NumStations++;
} else
{
planets[i].mass = DWordToScaledWord(manufactured[i].mass-1);
planets[i].mass += 0x3f0000;
planets[i].random_seed = manufactured[i].random_seed;
planets[i].parent = manufactured[i].parent;
planets[i].descriptioncode = manufactured[i].descriptioncode;
planets[i].orbital_radius = DWordToScaledWord(manufactured[i].orbital_radius);
planets[i].orbital_radius += 0x190000;
planets[i].latitude = manufactured[i].latitude;
planets[i].eccentricity = manufactured[i].eccentricity;
planets[i].longitude = manufactured[i].longitude;
planets[i].temperature = manufactured[i].temperature;
planets[i].field_3A = manufactured[i].field_3A;
planets[i].field_3C = manufactured[i].field_3C;
planets[i].rotspeed = manufactured[i].rotspeed;
planets[i].level = manufactured[i].level;
planets[i].model = manufactured[i].model;
GSystem_NumberOfMajorBodies++;
GSystem_namedobjects++;
if (manufactured[i].descriptioncode >= 32 && manufactured[i].descriptioncode <= 34)
{
GSystem_NumStations++;
GSystem_NumOrbiters++;
}
if (planets[i].parent == 0)
{
planets[i].orbital_period = 0;
} else
{
ScaledWord_t temp;
temp.full = getSqrt_adj(FFP_Div(FFP_Mul(FFP_Mul(planets[i].orbital_radius,
planets[i].orbital_radius),planets[i].orbital_radius),
planets[planets[i].parent-1].mass));
temp.w.Base = ((temp.w.Base*0x5EDB) >> 15);
planets[i].orbital_period = temp.full;
}
strcpy (planets[i].name, manufactured[i].name);
}
i++;
}
planets[i].mass = 0;
return i;
}
Note the difference in copying a city (description code 35, no parameters adjusted) and other bodies, where the odd constant is added to some parameters. My guess is that the original inputs are logical in some system, albeit not actual kms or AUs or something like that. Even worse is that the values produced by the routine // Planet_t: sizeof=0X44 // Holds data on each generated star, planet or moon object // Output of PlanetGenerator struct { dd mass; dd random_seed; dw parent; dw descriptioncode; dw model; dd orbital_radius; dw latitude; dd orbital_period; dd tempptr; dd field_1C; dw eccentricity; dw longitude; dw temperature; // in Kelvin db name[20]; dw field_3A; dw field_3C; db rotspeed; db level; dw field_40; dw field_42; } Planet_t; massThe mass of planets and stars is expressed in the games in Earth masses. Converting the binary value to the actual value goes like this: result = FractionMul(ScaledWordToDword(planets[i].mass-0x3f0000),43866, 0)>>2; The The result is the mass in Earth's masses times 100, so you want to convert it to a string using: printf ("Mass: %d.%02d Earth masses", result/100, result % 100);
To convert it to kilograms, multiply the result by 5.975 x 1024 and divide by 100 (obvious optimization left out for clarity!); at that point you should probably start using real floating point numbers... A sanity check would be to input the Earth mass as hardcoded above, including the conversion in random_seedThis is only useful if you know how to display objects from the 3D Object List. Drawing 3D objects can be influenced by numerous variables a well-known example is the little church with its real-time clock (the game time is also a variable). Though the number itself is generated at random, for every planet and/or city displayed it is generated in the same way, and thus is constant whenever something is drawn, resulting in the same cities and planets every time you see them. parentThis number indexes the parent of the object in the same list plus 1. For the main star or main Binary System it is always 0. In the Sol system code above you can see how every planet revolves around object #1 (the Sun), Daedalus orbits #2 (Mercury), and the Moon orbits #5 (the Earth). For cities it is (obviously) the planet on which they are located. Useful if you want to show a hierarchical tree of all objects in a stellar system. descriptioncodeThe text string to be displayed if you want information on any object. Take this string from the array modelThe index of the 3D model in the 3D Object List. Different from orbital_radiusThe distance from this to its parent object. Converted using result = ScaledWordToDword(FFP_Mul (planets[i].orbital_radius, 0xFFDB759A)); The result is the distance in 1000ths of an AU (Astronomical Unit). To get a real idea of the distances involved, multiply this number with 149597870 and divide by 1000; that's in km. For miles, multiply with 92955807 and divide by 1000. Displaying the distances as in the games goes like this: printf ("Distance: %d.%03d A.U.", result/1000, result % 1000);
latitudeFor cities this is the latitude, the angle between its vertical position and the equator. If a city is located on the Southern Hemisphere it is negative! It gets converted on input from 1/100ths of a degree to a binary value; check over there if you want to convert it back. For planets this should probably be labelled "declination" ("the angular distance on the celestial sphere north or south of the celestial equator" ssd.jpl.nasa.gov/glossary.html). Don't know how to use it for display, though. See also orbital_periodThe time it takes for this object to revolve once around its parent. The range of possible values is quite large, so there are three different equations: if (planets[i].orbital_period >= 0x1c0000)
{
result = ScaledWordToDword(FFP_Mul (planets[i].orbital_period, 0xffeb551f));
printf ("%d.%d years", result/10, result % 10);
} else
{
if (planets[i].orbital_period >= 0x140000)
{
result = ScaledWordToDword(FFP_Mul (planets[i].orbital_period, 0xfff06117));
printf ("%d days", result);
} else
{
result = ScaledWordToDword(FFP_Mul (planets[i].orbital_period, 0xfff548d1));
printf ("%d hours", result);
}
}
tempptrA temporary pointer to an instance of the actual 3D object to be used to display this object. Not used in my code. field_1CAhhh, those unknowns. As said before, most likely the infrared output of the planet or star. Used only to calculate the temperature of random generated planets and stars. In the predefined systems all temperatures are hardcoded so it's not used there. eccentricityThe amount in which the perfect orbit circle is flattened towards an ellipse. Look it up on the web if you want to know more about it. Though this is given sensible values it is not visible in the game, all orbit lines are drawn as perfect circles. Nitpick: due to the way the orbit lines are drawn, they are not perfect circles. Anyhow, they are not adjusted for eccentricity, so this statement still is true (for a given value of "true"). longitudeFor cities: the horizontal angle towards some arbritary vertical line. For planets it should probably be called "inclination" ("The angle between the vectors normal to the body's orbit plane and the specified reference plane" again from the NASA glossary). The vertical plane for our solar system is Earth's orbit, other planets are tilted above and below that. Visible in the game! Also no idea how to calculate and display in 3D. temperatureThe surface temperature in Kelvin. Subtract 273 to display in Kelvin, or perform your own calculation to convert to Fahrenheit. nameBeing only maximally 20 bytes long, it's just enough for "La Soeur du Dan Ham". As soon as planet and moon numbers are glued at the end of a star name you'll run into problems with names as "Groombridge 34", that's why they are ruthlessly snipped in the planet generator code. field_3A, field_3C, rotspeed, field_40, field_42To be honest, all unknowns. I once had an idea that levelThe level of nesting of moonlets into moons into planets into stars, eg., Sol has nesting level 0, Earth is 1, the Moon 2 and Galileo 3, and continuing on that, a spaceship orbiting Galileo would be 4 (and ejected cargo still in the gravity field of your ship would be 5). Useful to display a hierarchical tree of all objects in a single system. Wrapping things upCongratulations! As far as I can see, you can build your own universe from now on. (Should I have left out some crucial function or data array, just let me know!) If all's well you should end up with exactly the same map as in Frontier:First Encounters. There are some differences with Frontier: Elite 2 which aren't pursued in full. Examples of these are: In FE2, the star Olphiso (3,0) displays a small moon orbiting Olphiso 5, in FFE this moon disappeared miraculously (try fitting that in a story line).
The planet numbering in complicated systems such as Enethze
There are numerous optimizations possible; I just converted the original assembler to be working, not to be a prime example of coding. If you think a particular part could be rewritten in a somewhat clearer way, I urge you to do so but first of all test your new code! If there is the slightest possibility that the results are different anywhere in Frontier's Galaxy I will not use it!
The experienced coder can try to add and/or modify parameters. A well-known patch changes the Earth from a drab brown blob to something resembling a terraformed world (now you can see why). It is even fairly easy to add entirely new predefined systems and planets, and it would be fun to see those patched into, for example, JJFFE's sources. (You'll have to find the original routines in there first.) If you stick to just using it as an external map, FFEStarsys style, you can add new astronomical objects, such as Black holes, nebulae, Ringworld, or all kinds of alien planets. It is also easy to expand Human Space; one of my more successful patches to JJFFE reintroduced the colonized wormhole systems (and they appear exactly as in FE2), but, sadly, since I'm unable to retrace the wormhole jump bug, I can see them on the map but going there is a no-no... If you fully understand how the Human Systems are constructed you could invent an alien race (let's call them "Thargoids", shall we), pick any random star as "home base", set the parameters which govern their expansion and type of worlds they colonize. Make up a routine for the names of stars, planets, and cities ("hives"?), and include these new routines in your galaxy map. All fairly easy; it gets interesting if this alien sphere intersects the Human Colonized space! "Disputed system" would get a whole new meaning... A final note!Minor adjustments to the code will unevitably lead to a universe very similar to Frontier's, and if anyone is going to use it in a commercial project it would be interesting to see how much you'll have to change before Frontier Developments reckons it's not worth a law suit.
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. |