Generated from create.c with ROBODoc v3.2.2 on Sun Aug 27 19:47:33 2000
TABLE OF CONTENTS
- Create/Add_Center_Planet
- Create/Add_Circle_Home_Planet
- Create/Add_Circle_Stuff_Planets
- Create/Add_Core_Home_Planet
- Create/Add_Empty_Planets
- Create/Add_Extra_Circle_Stuff_Planets
- Create/Add_Extra_Home_Planets
- Create/Add_Stuff_Planets
- Create/CalcCirclegalaxysize
- Create/Randomize_Planet_Numbers
- Create/createGameDirectories
- Create/createPlayer
- Create/creategame
- Create/printGameSpecs
- Create/printPlanetStats
- Create/readGameSpec
- Create/swap_data
- GalaxyNG/Create
NAME
Add_Center_Planet -- add a planet in the exact centre of the galaxy.
SOURCE
void
Add_Center_Planet(game *aGame, int *planet_name)
{
planet *p;
p = addplanet(aGame);
(*planet_name)++;
p->x = round2(aGame->galaxysize / 2.0);
p->y = round2(aGame->galaxysize / 2.0);
p->size = 100.0;
p->producing = PR_DRIVE;
p->resources = round2(pow(2.0, frand2()));
}
NAME
Add_Circle_Home_Planet
NOTES
Currently not used since the code to create a circle game
has not yet been added to creategame().
NAME
Add_Circle_Stuff_Planets --
NAME
Add_Core_Home_Planet -- add a core home planet for a nation.
FUNCTION
Each nation has atleast one home planet. This is it's core home
planet. The other home planets are located around it. This
function allocates a core home planet. It makes sure that there
is a minimum distance between all core home planets. The core
home planets are all located on a big disc that fits inside the
square galaxy. The disc is used to prevent nations ending up in
one of the corners.
INPUTS
aGame -- game to add the planet to.
min_dist -- minimum distance between the core planets.
planet_name -- name of the previously added planet.
aPlayer -- nation the core planet will belong to.
RESULT
A core plane is added to the game's planet list. planet_name is
modified, will have the name (number) of this planet.
NAME
Add_Empty_Planets -- add some good size empty planets.
FUNCTION
This adds a number of good (relatively big sized) planets
around the core home planet of a nation.
The sum of the sizes of all these planets is about the
same for each nation.
SOURCE
void
Add_Empty_Planets(
game *aGame,
int nplanets, double empty_dist,
double x, double y,
int *planet_name,
double low_range, double up_range)
{
double tot_mass;
double *planet_sizes;
int cur_planet_nr;
double cur_total_size;
planet *p;
printf("o Adding empty planets.\n");
planet_sizes = alloc(nplanets * sizeof(double));
for (cur_planet_nr = 0;
cur_planet_nr < nplanets;
cur_planet_nr++)
planet_sizes[cur_planet_nr] = frand(MAXPOP - 80) + 80.0;
/* Adjust the Planet sizes in order to make sure that each players get * *
*
* * * * * * about the same total amount */
for (cur_total_size = 0.0, cur_planet_nr = 0;
cur_planet_nr < nplanets;
cur_planet_nr++)
cur_total_size += planet_sizes[cur_planet_nr];
for (;
(cur_total_size < nplanets * low_range) ||
(cur_total_size > nplanets * up_range);
) {
int pl_sel;
pl_sel = frand3(nplanets);
if (planet_sizes[pl_sel] > 100.0 && planet_sizes[pl_sel] < 980.0) {
if (cur_total_size > nplanets * up_range) {
(planet_sizes[pl_sel]) -= 10.0;
cur_total_size -= 10.0;
}
else {
(planet_sizes[pl_sel]) += 10.0;
cur_total_size += 10.0;
}
}
}
for (cur_planet_nr = 0, tot_mass = 0.0;
cur_planet_nr < nplanets;
cur_planet_nr++) {
double radius, angle;
double new_x, new_y;
int is_ok;
for (is_ok = FALSE; !is_ok;) {
is_ok = TRUE;
radius = 2.0 + frand(empty_dist - 2.0);
angle = frand(360.0) * (2 * 3.141592654 / 360.0);
new_x = x + sin(angle) * radius;
new_y = y + cos(angle) * radius;
if (new_x < 0 || new_x >= aGame->galaxysize)
is_ok = FALSE;
if (new_y < 0 || new_y >= aGame->galaxysize)
is_ok = FALSE;
}
p = addplanet(aGame);
(*planet_name)++;
p->x = round2(new_x);
p->y = round2(new_y);
p->size = planet_sizes[cur_planet_nr];
p->resources = round2(0.3 + pow(8.0, frand2()));
p->producing = PR_CAP;
tot_mass += (p->size) / (10.0 + 1.0 / p->resources);
printPlanetStats(p);
}
printf(" Total production mass: %.2f\n", tot_mass);
free(planet_sizes);
}
NAME
Add_Extra_Circle_Stuff_Planets
NAME
Add_Extra_Home_Planets
FUNCTION
In addition to its core home planet a nation can have
a number of additional home planets. This functions adds these.
They are added randomly on a donut shape disk centered around
the core home planet. The donut hole has a radius of 1, and the
donut disk has a radius of 3.
NOTES
The radius number 1 and 3 should be configurable.
SOURCE
void
Add_Extra_Home_Planets(
game *aGame,
newplayer *aNewPlayer,
double x, double y,
int *planet_name,
player *aPlayer)
{
int cur_extra_home;
planet *p;
printf("o Adding secondary home planets.\n");
for (cur_extra_home = 1;
cur_extra_home < aNewPlayer->numberOfHomePlanets;
cur_extra_home++) {
double radius, angle;
double new_x, new_y;
int is_ok;
for (is_ok = FALSE; !is_ok;) {
is_ok = TRUE;
radius = 1.0 + frand(2.0);
angle = frand(360.0) * (2 * 3.141592654 / 360.0);
new_x = x + sin(angle) * radius;
new_y = y + cos(angle) * radius;
if (new_x < 0 || new_x >= aGame->galaxysize)
is_ok = FALSE;
if (new_y < 0 || new_y >= aGame->galaxysize)
is_ok = FALSE;
}
p = addplanet(aGame);
(*planet_name)++;
p->x = round2(new_x);
p->y = round2(new_y);
p->owner = aPlayer;
p->size = aNewPlayer->coreSizes[cur_extra_home];
p->producing = PR_DRIVE;
p->resources = 10;
p->pop = aNewPlayer->coreSizes[cur_extra_home];
p->ind = aNewPlayer->coreSizes[cur_extra_home];
printPlanetStats(p);
}
}
NAME
Add_Stuff_Planets -- add a number of stuff planets.
SYNOPSIS
void Add_Stuff_Planets(game *, int, int *)
Add_Stuff_Planets(aGame, stuff_planets, planet_name)
FUNCTION
Stuff planets are small useless planets that are randomly
scattered accross the galaxy to fill up the empty space
between the empires.
INPUTS
aGame -- game to add the planets to.
stuff_planets -- the number of stuff planets to be added.
planet_name -- the name (number) of the previous planet.
RESULT
A number of planet are added to the game's planet list.
planet_name is modified, will have the name (number) of
the last planet that was added.
SOURCE
void
Add_Stuff_Planets(game *aGame, int stuff_planets, int *planet_name)
{
int cur_planet_nr;
planet *p;
for (cur_planet_nr = 0;
cur_planet_nr < stuff_planets;
cur_planet_nr++) {
p = addplanet(aGame);
(*planet_name)++;
p->x = round2(frand(aGame->galaxysize));
p->y = round2(frand(aGame->galaxysize));
p->size = 2.0 + frand(170.0);
p->resources = round2(pow(2.0, frand2()));
p->producing = PR_CAP;
}
}
NAME
CalcCirclegalaxysize
NAME
Randomize_Planet_Numbers -- shuffle planet names.
FUNCTION
Randomly shuffle the planet names. The method used is randomly
selecting two planets and swapping all their data. This process
is repeated 2000 times. The names are randomized to prevent
players from guessing which planets are the good planets and bad
planets around the nations core home planets.
NOTES
This is not a particular good or speedy way of shuffling.
Someone suggested a much faster method, but that got misplaced.
SOURCE
void
Randomize_Planet_Numbers(game *aGame)
{
int total_nr_of_planets;
planet *p;
int randomizor;
for (p = aGame->planets, total_nr_of_planets = 0; p; p = p->next) {
total_nr_of_planets++;
}
for (randomizor = 0; randomizor < 2000; randomizor++) {
int pln1, pln2, nm;
planet *p1, *p2;
pln1 = rand() % total_nr_of_planets;
pln2 = rand() % total_nr_of_planets;
for (p1 = aGame->planets, nm = 0;
nm < pln1;
p1 = p1->next, nm++);
for (p2 = aGame->planets, nm = 0;
nm < pln2;
p2 = p2->next, nm++);
if (!p1->owner && !p2->owner) {
player *temp;
temp = p2->owner;
p2->owner = p1->owner;
p1->owner = temp;
swap_data(&p1->x, &p2->x);
swap_data(&p1->y, &p2->y);
swap_data(&p1->size, &p2->size);
swap_data(&p1->pop, &p2->pop);
swap_data(&p1->ind, &p2->ind);
swap_data(&p1->resources, &p2->resources);
}
}
}
NAME
createGameDirectories --
FUNCTION
Creates a number of sub directories that are used to store
files of a game. Each subdirectory has the same name as
the game. They are created in the directories:
reports/
orders/
statistics/
INPUTS
name -- name of the game
SOURCE
int
createGameDirectories(char *name)
{
sprintf(lineBuffer, "%s/data/%s", galaxynghome, name);
if (GOS_mkdir(lineBuffer, 0700)) {
// fprintf(stderr, "Warning a game under that name already exists\n");
// fprintf(stderr, "Do you want to continue [y/n]?\n");
// scanf("%s", lineBuffer);
// if (*lineBuffer != 'y')
// return FALSE;
}
else {
sprintf(lineBuffer, "%s/reports/%s", galaxynghome, name);
GOS_mkdir(lineBuffer, 0700);
sprintf(lineBuffer, "%s/orders/%s", galaxynghome, name);
GOS_mkdir(lineBuffer, 0700);
sprintf(lineBuffer, "%s/statistics/%s", galaxynghome, name);
GOS_mkdir(lineBuffer, 0700);
}
return TRUE;
}
NAME
createPlayer -- allocate and initialize a player structure.
SYNOPSIS
player *createPlayer(game *aGame, newplayer *aNewPlayer)
FUNCTION
RESULT
Pointer to an initialized player structure.
SOURCE
player *
createPlayer(game *aGame, newplayer *aNewPlayer)
{
player *aPlayer;
aPlayer = allocStruct(player);
setName(aPlayer, aNewPlayer->name);
aPlayer->pswd = strdup(aNewPlayer->pswd);
aPlayer->addr = strdup(aNewPlayer->addr);
aPlayer->realName = strdup("none");
aPlayer->pswdstate = 1;
aPlayer->drive = 1;
aPlayer->weapons = 1;
aPlayer->shields = 1;
aPlayer->cargo = 1;
aPlayer->msize = aGame->galaxysize;
aPlayer->flags =
F_ANONYMOUS | F_AUTOUNLOAD | F_PRODTABLE | F_SORTGROUPS |
F_GROUPFORECAST | F_PLANETFORECAST | F_SHIPTYPEFORECAST |
F_ROUTESFORECAST;
/* | F_XMLREPORT ; */
/* F_MACHINEREPORT */
return aPlayer;
}
NAME
creategame -- create a game based on a gamespecification.
SYNOPSIS
game *creategame(gamespecification *)
newGame = creategame(aGameSpec)
FUNCTION
Creates all nations. For each nation a number
of planets are created and intialized. The number
of nations and number of planets are defined in the
game specification.
RESULT
Pointer to an initialized game structure.
SOURCE
game *
creategame(gamespecification *aGameSpec)
{
if (createGameDirectories(aGameSpec->name)) {
int planet_name;
newplayer *aNewPlayer;
game *aGame;
srand((int) time(NULL));
resetErnie(197162622 + (rand() & 0xFF));
aGame = allocStruct(game);
setName(aGame, aGameSpec->name);
aGame->turn = 0;
aGame->galaxysize = aGameSpec->galaxySize;
planet_name = 1; /* Do not change this! planets can be * *
* * looked up by number and this function
* * * * * expects the first planet to
* have * number * * * 1 */
for (aNewPlayer = aGameSpec->players;
aNewPlayer;
aNewPlayer = aNewPlayer->next) {
planet *core_planet;
player *aPlayer;
aPlayer = createPlayer(aGame, aNewPlayer);
printf("o Adding player %s\n", aPlayer->name);
addList(&(aGame->players), aPlayer);
if ((core_planet =
Add_Core_Home_Planet(aGame, aGameSpec->minDist,
&planet_name, aPlayer,
aNewPlayer->coreSizes[0]))) {
double x, y;
x = core_planet->x;
y = core_planet->y;
if (aNewPlayer->numberOfHomePlanets > 1) {
Add_Extra_Home_Planets(aGame, aNewPlayer, x, y,
&planet_name, aPlayer);
}
if (aGameSpec->numberOfEmptyPlanets) {
Add_Empty_Planets(aGame, aGameSpec->numberOfEmptyPlanets,
aGameSpec->radiusEmptyPlanets, x, y,
&planet_name,
600.0, 700.0);
}
if (aGameSpec->numberOfStuffPlanets) {
Add_Stuff_Planets(aGame,
aGameSpec->numberOfStuffPlanets,
&planet_name);
}
}
else {
printf("Can't space homeworlds at least %f light years apart.\n",
aGameSpec->minDist);
printf("Please try again with a larger sized galaxy.\n");
return NULL;
}
}
/* Add_Center_Planet(aGame, &planet_name); */
Randomize_Planet_Numbers(aGame);
preComputeGroupData(aGame);
nationStatus(aGame);
return aGame;
}
else {
return NULL;
}
}
NAME
printGameSpecs -- print the game specs.
SYNOPSIS
void printGameSpecs(gamespecification *aGameSpec)
SOURCE
void
printGameSpecs(gamespecification *aGameSpec)
{
newplayer *curNewPlayer;
aGameSpec->gameOptions = 0;
printf("Galaxy: %s\n", aGameSpec->name);
printf("Size: %.0f x %.0f\n",
aGameSpec->galaxySize, aGameSpec->galaxySize);
printf("Nations: %d\n", aGameSpec->numberOfPlayers);
printf("Home planets/nation: %d\n", aGameSpec->numberOfHomePlanets);
printf("Spacing nations: %.1f\n", aGameSpec->minDist);
printf("Empty planets/nation: %d\n", aGameSpec->numberOfEmptyPlanets);
printf("Located in within a: %.1f radius\n", aGameSpec->radiusEmptyPlanets);
printf("Stuff planets/nation: %d\n", aGameSpec->numberOfStuffPlanets);
for (curNewPlayer = aGameSpec->players;
curNewPlayer;
curNewPlayer = curNewPlayer->next) {
printf("%s played by %s with password %s\n",
curNewPlayer->name, curNewPlayer->addr, curNewPlayer->pswd);
}
}
NAME
printPlanetStats
SOURCE
void
printPlanetStats(planet *p)
{
printf(" Planet %s %.2f %.2f %.2f %.2f\n",
p->name, p->size, p->pop,
p->ind, p->resources);
}
SYNOPSIS
gamespecification *readGameSpec(FILE *)
spec = readGameSpec(specfile)
FUNCTION
Reads and interprets a file that specifies the layout of the
galaxy, and information about the players.
RESULT
Pointer to a gamespecification structure. Any parameters
not defined in the specification file are given some
"sensible" default.
SEE ALSO
See Doc/example.glx for information on the layout of such a file.
CMD_template()
SOURCE
gamespecification *
readGameSpec(FILE * specfile)
{
gamespecification *aGameSpec;
char *isRead;
char *key;
char *value;
srand((int) time(NULL));
aGameSpec = allocStruct(gamespecification);
setName(aGameSpec, "TestGame");
aGameSpec->gameOptions = 0;
aGameSpec->galaxySize = 200;
aGameSpec->numberOfHomePlanets = 2;
aGameSpec->numberOfEmptyPlanets = 6;
aGameSpec->numberOfStuffPlanets = 5;
aGameSpec->minDist = 25.0;
aGameSpec->radiusEmptyPlanets = 30.0;
aGameSpec->players = NULL;
aGameSpec->numberOfPlayers = 0;
aGameSpec->coreSizes = malloc(2 * sizeof(double));
aGameSpec->coreSizes[0] = 1000.0;
aGameSpec->coreSizes[1] = 400.0;
for (isRead = fgets(lineBuffer, LINE_BUFFER_SIZE, specfile);
isRead;
isRead = fgets(lineBuffer, LINE_BUFFER_SIZE, specfile)) {
key = getstr(lineBuffer);
if (key[0] != '\0') {
if (noCaseStrcmp("player", key) == 0) {
newplayer *aNewPlayer;
char nationName[20];
aNewPlayer = allocStruct(newplayer);
aNewPlayer->addr = strdup(getstr(0));
(aGameSpec->numberOfPlayers)++;
sprintf(nationName, "Nation_%d", aGameSpec->numberOfPlayers);
setName(aNewPlayer, nationName);
sprintf(nationName, "P%d", rand());
aNewPlayer->pswd = strdup(nationName);
addList(&(aGameSpec->players), aNewPlayer);
for (value = getstr(0), aNewPlayer->numberOfHomePlanets = 0;
value[0] != '\0';
value = getstr(0), aNewPlayer->numberOfHomePlanets++);
if (aNewPlayer->numberOfHomePlanets) {
int i;
aNewPlayer->coreSizes =
malloc(aNewPlayer->numberOfHomePlanets * sizeof(double));
getstr(lineBuffer);
getstr(0); /* skip address */
for (value = getstr(0), i = 0;
value[0] != '\0';
value = getstr(0), i++) {
aNewPlayer->coreSizes[i] = atof(value);
}
}
else {
int i;
aNewPlayer->coreSizes =
malloc(aGameSpec->numberOfHomePlanets * sizeof(double));
for (i = 0;
i < aGameSpec->numberOfHomePlanets;
i++) {
aNewPlayer->coreSizes[i] = aGameSpec->coreSizes[i];
}
aNewPlayer->numberOfHomePlanets = aGameSpec->numberOfHomePlanets;
}
}
else if (noCaseStrcmp("size", key) == 0) {
value = getstr(0);
aGameSpec->galaxySize = atof(value);
}
else if (noCaseStrcmp("nation_spacing", key) == 0) {
value = getstr(0);
aGameSpec->minDist = atof(value);
}
else if (noCaseStrcmp("empty_planets", key) == 0) {
value = getstr(0);
aGameSpec->numberOfEmptyPlanets = atoi(value);
}
else if (noCaseStrcmp("stuff_planets", key) == 0) {
value = getstr(0);
aGameSpec->numberOfStuffPlanets = atoi(value);
}
else if (noCaseStrcmp("empty_radius", key) == 0) {
value = getstr(0);
aGameSpec->radiusEmptyPlanets = atof(value);
}
else if (noCaseStrcmp("nation_spacing", key) == 0) {
value = getstr(0);
aGameSpec->minDist = atof(value);
}
else if (noCaseStrcmp("name", key) == 0) {
setName(aGameSpec, getstr(0));
}
else if (noCaseStrcmp("core_sizes", key) == 0) {
int number;
for (value = getstr(0), aGameSpec->numberOfHomePlanets = 0;
value[0] != '\0';
value = getstr(0), aGameSpec->numberOfHomePlanets++);
aGameSpec->coreSizes =
malloc(aGameSpec->numberOfHomePlanets * sizeof(double));
getstr(lineBuffer);
for (value = getstr(0), number = 0;
value[0] != '\0';
value = getstr(0), number++) {
aGameSpec->coreSizes[number] = atof(value);
}
}
else {
printf("Unknown key %s\n", key);
}
}
}
return aGameSpec;
}
NAME
swap_data -- swap two doubles
SYNOPSIS
void swap_data(double *v1, double *v2)
NAME
Create -- create a new galaxy
NOTES
This code was developed since we found that the old code
sometimes created galaxies that left some nations in rather
unfair positions. That is some nations would have their home
planet located far away from other planets, while others nations
home planets were located near a whole bunch of good planets.
The code tries to provide all player with an equal chance on
success, while still keeping the layout of the galaxy diverse
and interesting.
How is this accomplised:
(1) Each nation will get the same number of planets within a
circle of a given radius. The size of these planets differ
but the total sum of the sizes is the same for all nations.
The resources of the planets are still chosen random.
(2) The home world can be spaced widely from eachother, ensuring
that a nation isn't kicked out in the first few turns.
(3) To improve the tactical possibilities a number of `stuff
planets' will be scattered across the galaxy. These are
small useless planets that provide players with different
routes to attack their enemies.
(4) In addition it is possible to let the nations start with
more than one home planet, this will speed up the game.
All these options can be controled with a set of variables
that you will be asked to supply when you the galaxy
program to create a new galaxy. A large number of
different galaxies is thus possible. Try to experiment a
little before you settle on a galaxy you like.
Notice that as opposed to the original code the names of
the nations at turn zero will not be Player_xx but
Nation_xx.
Added the option to space out the empires along the edge of
a large circle, in order to make certain that no one got
a better placement geographically than any other player.
No attempt was made to ensure any seeding of players. If
you get stuck between Jacco and Frans, you are still toast. :)
Tommy 980629
AUTHOR
Frans, Rogerio Fung, Tommy
BUGS
You found bugs?
Catch them in a jar and send them to fslothouber@acm.org