Generated from phase.c with ROBODoc v3.2.2 on Sun Aug 27 19:47:34 2000
TABLE OF CONTENTS
- GalaxyNG/Phase
- Phase/bombPlanet
- Phase/bombphase
- Phase/cktech
- Phase/convertcap
- Phase/determineOwnership
- Phase/fleetphase
- Phase/ftrunc2
- Phase/interceptphase
- Phase/joinphase
- Phase/kill
- Phase/loadphase
- Phase/movephase
- Phase/mustBomb
- Phase/nametocargotype
- Phase/produceMatCap
- Phase/producePopulation
- Phase/produceShip
- Phase/produceTechnology
- Phase/producephase
- Phase/sortphase
- Phase/unloadcap
- Phase/unloadcol
- Phase/unloadgroup
- Phase/unloadphase
NAME
Phase -- functions to compute the different phases in a turn.
BUGS
At the moment the intercept phase is pretty buggy.
If there are loops or paths, that is a group intercepts
on a planet where there are groups that intercept an
another planet the outcome of the algorithm is pretty random.
NAME
bombPlanet -- bomb a planet.
FUNCTION
Depending on the preferences of the GM all live and industry
on the planet is
(a) completely destroyed, cap and mat are wiped out too.
(b) reduced to 25%, cap and mat are untouched.
SOURCE
void
bombPlanet(game *aGame, planet *p)
{
p->col = 0;
p->producing = PR_CAP;
p->producingshiptype = 0;
p->inprogress = 0;
memset(p->routes, 0, sizeof(p->routes));
if (aGame->gameOptions & GAME_NONGBOMBING) {
p->pop = 0;
p->ind = 0;
p->cap = 0;
p->mat = 0;
p->spent = 0;
}
else {
p->pop = p->pop * 0.25;
p->ind = p->ind * 0.25;
p->spent = 0;
convertcap(p);
}
}
NAME
bombphase -- bomb planets
SYNOPSIS
void bombphase(game *aGame)
FUNCTION
Examine which nations have armed ships over a planet.
If there are any, the planets are bombed and it is
determined who should own the planet.
SOURCE
void
bombphase(game *aGame)
{
player *aPlayer;
for (aPlayer = aGame->players;
aPlayer;
aPlayer = aPlayer->next) {
group *attackGroup;
for (attackGroup = aPlayer->groups;
attackGroup;
attackGroup = attackGroup->next) {
if (mustBomb(aPlayer, attackGroup)) {
planet *targetPlanet;
bombing *aBombing;
player *viewingPlayer;
targetPlanet = attackGroup->location;
aBombing = allocStruct(bombing);
setName(aBombing, targetPlanet->name);
/* This should be a function */
aBombing->where = targetPlanet;
aBombing->owner = targetPlanet->owner;
aBombing->pop = targetPlanet->pop;
aBombing->ind = targetPlanet->ind;
aBombing->producing = targetPlanet->producing;
aBombing->producingshiptype = targetPlanet->producingshiptype;
aBombing->cap = targetPlanet->cap;
aBombing->mat = targetPlanet->mat;
aBombing->col = targetPlanet->col;
aBombing->viewers = NULL;
for (viewingPlayer = aGame->players;
viewingPlayer;
viewingPlayer = viewingPlayer->next) {
if (canseeplanet(viewingPlayer, targetPlanet)) {
alliance *a;
a = allocStruct(alliance);
a->who = viewingPlayer;
addList(&aBombing->viewers, a);
}
}
if (aGame->gameOptions & GAME_NONGBOMBING) {
targetPlanet->owner = NULL;
}
else {
targetPlanet->owner =
determineOwnership(aGame, targetPlanet, aPlayer);
}
plog(LPART, "Nation %s bombs planet %s\n",
aPlayer->name, targetPlanet->name);
if (targetPlanet->owner) {
plog(LPART, "Ownership goes to %s\n", targetPlanet->owner->name);
aBombing->who = targetPlanet->owner;
}
else {
plog(LPART, "Ownership goes to nobody, planet neutral\n");
aBombing->who = aPlayer;
}
addList(&(aGame->bombings), aBombing);
bombPlanet(aGame, targetPlanet);
}
}
}
}
NAME
cktech -- check tech levels of a group.
FUNCION
Clip all tech levels of a group to two decimal points.
Set tech levels of zero components to zero.
NOTES
This should be in util.c
SOURCE
void
cktech(group *g)
{
shiptype *t;
t = g->type;
g->drive = ftrunc2(g->drive);
g->weapons = ftrunc2(g->weapons);
g->shields = ftrunc2(g->shields);
g->cargo = ftrunc2(g->cargo);
if (!t->drive)
g->drive = 0;
if (!t->attacks)
g->weapons = 0;
if (!t->shields)
g->shields = 0;
if (!t->cargo)
g->cargo = 0;
}
NAME
convertcap -- convert capital into industry.
SYNOPSIS
void convertcap(planet *p)
SOURCE
void
convertcap(planet *p)
{
double indinc;
indinc = p->pop - p->ind;
if (indinc > p->cap)
indinc = p->cap;
p->cap -= indinc;
p->ind += indinc;
}
NAME
determineOwnership -- determine ownership of planet after bombing.
FUNCTION
Determines which nation should get a planet after it is bombed.
NAME
fleetphase -- update fleet data
FUNCTION
Remove fleets that have no groups left. Recompute the speed of
each fleet. The speed might have changed due to upgrades or loss
of slow ships in battles.
SEE ALSO
fleetSpeed()
SOURCE
void
fleetphase(game *aGame)
{
player *P;
fleetname *fl, *fl2;
group *g;
/* double shipspeed; */
int hasships;
pdebug(DFULL, "Fleet Phase\n");
for (P = aGame->players; P; P = P->next) {
for (fl = P->fleetnames; fl; fl = fl2) {
fl2 = fl->next;
hasships = FALSE;
for (g = P->groups; g; g = g->next) {
if (g->thefleet eq fl) {
fl->fleetspeed = groupSpeed(g); /* This can be * * removed
* I * * * think! FS */
hasships = TRUE;
break;
}
}
fl->fleetspeed = fleetSpeed(fl, P->groups); /* CB-19980922 * */
pdebug(DFULL, "Fleet %s speed %f\n", fl->name, fl->fleetspeed);
if (!hasships) {
pdebug(DFULL, "Removing Fleet %s\n", fl->name);
remList(&P->fleetnames, fl);
}
}
}
}
NAME
ftrunc2 -- clip a number to two decimal points.
SYNOPSIS
double ftrunc2(double x)
NOTES
Should use lineBuffer.
SOURCE
double
ftrunc2(double x)
{
char buf[32];
sprintf(buf, "%0.2f", x);
return atof(buf);
}
NAME
interceptphase -- compute the destination of intercepting groups and
fleets.
SYNOPSIS
void interceptphase(game *aGame)
FUNCTION
Compute the destination of all groups and fleets that have been
given the intercept command.
NOTES
This does not work perfectly, groups can end up unexpected locations.
SOURCE
void
interceptphase(game *aGame)
{
player *curPlayer, *otherPlayer;
double *massPerPlanet;
int noPlanets;
pdebug(DFULL, "Intercept Phase\n");
noPlanets = numberOfElements(aGame->planets);
massPerPlanet = (double *) alloc((noPlanets + 1) * sizeof(double));
for (curPlayer = aGame->players;
curPlayer;
curPlayer = curPlayer->next) {
group *inGroup;
for (inGroup = curPlayer->groups; inGroup; inGroup = inGroup->next) {
if (inGroup->flags & GF_INTERCEPT) {
double maxDist, maxMass;
planet *inPlanet, *targetPlanet, *curPlanet;
int planetIndex;
if (inGroup->thefleet)
maxDist = 2 * inGroup->thefleet->fleetspeed;
else
maxDist = 2 * groupSpeed(inGroup);
inPlanet = inGroup->where;
if (inGroup->thefleet) {
pdebug(DFULL, "Fleet %s Intercept on Planet %s max Dist %f\n",
inGroup->thefleet->name,
inPlanet->name,
maxDist);
}
else {
pdebug(DFULL, "Group %d Intercept on Planet %s max Dist %f\n",
inGroup->number,
inPlanet->name,
maxDist);
}
/*
* Compute the total mass per destination planet, of all groups departing
* from the planet the intercept command was issued on. Destination
* planet have to be with in two turn range. */
memset(massPerPlanet, 0, (noPlanets + 1) * sizeof(double));
for (otherPlayer = aGame->players;
otherPlayer;
otherPlayer = otherPlayer->next) {
if (otherPlayer != curPlayer) {
group *aGroup;
for (aGroup = otherPlayer->groups;
aGroup;
aGroup = aGroup->next) {
if ((aGroup->dist) &&
(aGroup->location eq inPlanet) &&
(dist(aGroup->where, inGroup->location) < maxDist)) {
massPerPlanet[ptonum(aGame->planets, aGroup->where)] +=
aGroup->ships * shipmass(aGroup);
}
}
}
}
/*
* Find the destination planet of the largest outgoing mass. */
targetPlanet = NULL;
for (curPlanet = aGame->planets, planetIndex = 1, maxMass = 0;
curPlanet;
planetIndex++, curPlanet = curPlanet->next) {
assert(planetIndex < (noPlanets + 1));
if (massPerPlanet[planetIndex] > maxMass) {
targetPlanet = curPlanet;
maxMass = massPerPlanet[planetIndex];
}
}
if (targetPlanet) {
pdebug(DFULL, "Result: Planet %s (%f ly away).\n",
targetPlanet->name,
dist(inGroup->where, targetPlanet));
inGroup->where = inGroup->from;
send(inGroup, targetPlanet);
}
inGroup->flags &= ~GF_INTERCEPT; /* Remove the * *
* intercept * * * * * *
* flag. */
}
}
}
free(massPerPlanet);
}
NAME
joinphase -- join similar groups into a single group.
SYNOPSIS
void joinphase(game *aGame)
NAME
kill --
NOTES
Should be in battle.c I guess.
NAME
loadphase -- upload cargo from planet onto ships
FUNCTION
Takes care of all cargo routes.
NAME
movephase -- ships move through hyperspace
FUNCTION
Advance all ships (groups and fleets) through hyperspace.
The distance they travel depend on the drive, drive tech,
and total mass of the ship (including cargo).
NOTES
Should use groupSpeed() and fleetSpeed()
SEE ALSO
shipmass()
NAME
mustBomb -- must a nation bomb a planet?
SYNOPSIS
int mustBomb(player *P, group *g)
FUNCTION
Determine of a nation is obliged to bomb a planet.
RESULT
TRUE -- yes the nation should bomb.
FALSE -- no the nation should not.
SOURCE
int
mustBomb(player *P, group *g)
{
int must_bomb;
must_bomb = g->location && g->location->owner && g->ships &&
g->type->attacks && atwar(P, g->location->owner);
return must_bomb;
}
NAME
nametocargotype --
SYNOPSIS
int nametocargotype(char *s)
NOTES
Should be in Util
NAME
produceMatCap -- Produce CAP or MAT.
NOTE
The function to compute the CAP increase is a tricky one.
SOURCE
void
produceMatCap(planet *aPlanet, double industry)
{
double materialDemand;
switch (aPlanet->producing) {
case PR_CAP:
materialDemand = industry / INDPERCAP; /* 1 unit of MAT per 1 CAP
*
* * * * */
if (materialDemand > aPlanet->mat)
materialDemand = aPlanet->mat;
industry -= materialDemand * INDPERCAP;
aPlanet->cap += materialDemand;
aPlanet->mat -= materialDemand;
aPlanet->cap += industry / (INDPERCAP + 1 / aPlanet->resources);
break;
case PR_MAT:
aPlanet->mat += industry * aPlanet->resources;
break;
default:
assert(0);
}
aPlanet->inprogress = 0.0;
}
NAME
producePopulation -- growth of population and colonists.
FUNCTION
Lets the population of a planet grow. Excess population
(growth beyond the size of the planet) is turned into colonists
by condensing a number of persons into one colonist.
SOURCE
void
producePopulation(planet *aPlanet)
{
double popinc, poproom;
if (aPlanet->owner) {
popinc = aPlanet->pop * POPINC;
poproom = aPlanet->size - aPlanet->pop;
if (poproom > popinc)
poproom = popinc;
aPlanet->pop += poproom;
aPlanet->col += (popinc - poproom) / POPPERCOL;
convertcap(aPlanet);
}
}
NAME
produceShip -- try to produce some ships.
FUNCTION
Computes based on the amount of industry (points) how many ships
can be build. If this is 1 or more the ships are produces and a
new group with these ships is created. If it is less than 1 the
production is delayed to the next turn.
NOTE
Because of MAT the expression to compute the number of ships
that can be produced is a tricky one.
SOURCE
void
produceShip(planet *aPlanet, double industry)
{
int n, numberOfShips;
shiptype *typeProduced;
double typeMass, indForProduction, indForMaterials;
typeProduced = aPlanet->producingshiptype;
typeMass = typemass(typeProduced);
typeMass = typeMass - 0.01; /* Fudge Factor, cause people
keep on building those 99.01 ships and then complain they get not
build */
for (n = (int) (industry / (typeMass * INDPERSHIP)) + 1, numberOfShips = 0;
n >= 0;
n--) {
indForProduction = n * typeMass * INDPERSHIP;
indForMaterials = (n * typeMass - aPlanet->mat) / aPlanet->resources;
if (indForMaterials < 0)
indForMaterials = 0;
if (indForProduction + indForMaterials <= industry) {
numberOfShips = n;
break;
}
}
if (numberOfShips == 0) {
/* Delay Construction to next turn */
aPlanet->inprogress = industry;
}
else {
group *aGroup;
player *aPlayer;
aPlayer = aPlanet->owner;
indForProduction = numberOfShips * typeMass * INDPERSHIP;
indForMaterials = (numberOfShips * typeMass - aPlanet->mat)
/ aPlanet->resources;
if (indForMaterials < 0) {
indForMaterials = 0;
aPlanet->mat -= numberOfShips * typeMass;
}
else {
aPlanet->mat = 0;
}
industry -= indForProduction + indForMaterials;
aPlanet->inprogress = industry;
/* This Should be a function */
aGroup = allocStruct(group);
aGroup->ships = numberOfShips;
aGroup->type = typeProduced;
aGroup->drive = aPlayer->drive;
aGroup->weapons = aPlayer->weapons;
aGroup->shields = aPlayer->shields;
aGroup->cargo = aPlayer->cargo;
cktech(aGroup);
aGroup->load = 0;
aGroup->loadtype = CG_EMPTY;
aGroup->from = aGroup->where = aPlanet;
aGroup->dist = 0;
aGroup->thefleet = NULL;
aGroup->defense = 0.0;
aGroup->attack = 0.0;
aGroup->flags = 0;
aGroup->location = aPlanet;
numberGroup(aPlayer, aGroup);
addList(&aPlayer->groups, aGroup);
aPlayer->massproduced += numberOfShips * typemass(typeProduced);
}
}
NAME
produceTechnology -- produce different kind of technologies.
SOURCE
void
produceTechnology(planet *aPlanet, double industry)
{
player *aPlayer;
aPlayer = aPlanet->owner;
switch (aPlanet->producing) {
case PR_DRIVE:
aPlayer->drive += industry / 5000.0;
plog(LFULL, "Producing DRIVE %lf\n", industry / 5000.0);
break;
case PR_WEAPONS:
aPlayer->weapons += industry / 5000.0;
plog(LFULL, "Producing WEAPONS %lf\n", industry / 5000.0);
break;
case PR_SHIELDS:
aPlayer->shields += industry / 5000.0;
plog(LFULL, "Producing SHIELDS %lf\n", industry / 5000.0);
break;
case PR_CARGO:
aPlayer->cargo += industry / 2500.0;
plog(LFULL, "Producing CARGO %lf\n", industry / 2500.0);
break;
default:
assert(0);
}
aPlanet->inprogress = 0.0;
}
NAME
producephase -- planets produce their products.
FUNCTION
Iterate over all planets and let each planet produce its thing.
Also takes care of the population and colonist increase.
SOURCE
void
producephase(game *aGame)
{
planet *aPlanet;
pdebug(DFULL, "Produce Phase\n");
for (aPlanet = aGame->planets;
aPlanet;
aPlanet = aPlanet->next) {
if (aPlanet->owner) {
double industry;
switch (aPlanet->producing) {
case PR_SHIP:
industry = aPlanet->ind * .75 + aPlanet->pop * .25 - aPlanet->spent +
aPlanet->inprogress;
aPlanet->spent = 0.0;
produceShip(aPlanet, industry);
break;
case PR_MAT:
case PR_CAP:
industry = aPlanet->ind * .75 + aPlanet->pop * .25 - aPlanet->spent +
aPlanet->inprogress;
aPlanet->spent = 0.0;
produceMatCap(aPlanet, industry);
break;
}
}
}
for (aPlanet = aGame->planets;
aPlanet;
aPlanet = aPlanet->next) {
if (aPlanet->owner) {
double industry;
switch (aPlanet->producing) {
case PR_DRIVE:
case PR_WEAPONS:
case PR_SHIELDS:
case PR_CARGO:
industry = aPlanet->ind * .75 + aPlanet->pop * .25 - aPlanet->spent +
aPlanet->inprogress;
aPlanet->spent = 0.0;
produceTechnology(aPlanet, industry);
break;
}
producePopulation(aPlanet);
}
}
}
NAME
sortphase -- renumber the groups
SYNOPSIS
void sortphase(game *aGame)
FUNCTION
Renumber the groups such that they are sorted according
to planet. In particular they are number in the following
order:
(1) groups at planets owned by the nation,
(2) groups at planets owned by other nations,
(3) groups at all other planets,
(4) groups that are part of a fleet.
SOURCE
void
sortphase(game *aGame)
{
player *P;
group *g;
planet *p;
fleetname *fl;
int n;
pdebug(DFULL, "Sort Phase\n");
for (P = aGame->players; P; P = P->next) {
n = 1;
if (P->flags & F_SORTGROUPS) {
/* Groups at planets owned by the nation */
for (p = aGame->planets; p; p = p->next) {
if (p->owner == P) {
for (g = P->groups; g; g = g->next) {
if (g->location == p && !g->thefleet) {
g->number = n;
n++;
}
}
for (g = P->groups; g; g = g->next) {
if (!g->location && g->where == p && !g->thefleet) {
g->number = n;
n++;
}
}
}
}
/* Groups at planets owned by other nations */
for (p = aGame->planets; p; p = p->next) {
if (p->owner && p->owner != P) {
for (g = P->groups; g; g = g->next) {
if (g->location == p && !g->thefleet) {
g->number = n;
n++;
}
}
for (g = P->groups; g; g = g->next) {
if (!g->location && g->where == p && !g->thefleet) {
g->number = n;
n++;
}
}
}
}
/* Groups at all other planets */
for (p = aGame->planets; p; p = p->next) {
if (!p->owner) {
for (g = P->groups; g; g = g->next) {
if (g->location == p && !g->thefleet) {
g->number = n;
n++;
}
}
for (g = P->groups; g; g = g->next) {
if (!g->location && g->where == p && !g->thefleet) {
g->number = n;
n++;
}
}
}
}
/* Groups that are part of fleets */
for (fl = P->fleetnames; fl; fl = fl->next) {
for (g = P->groups; g; g = g->next) {
if (g->thefleet eq fl) {
g->number = n;
n++;
}
}
}
}
}
}
NAME
unloadcap -- unload capital.
SYNOPSIS
void unloadcap(planet *p, double x)
FUNCTION
Unload capital unto a planet and if possible use it to
increase the industry.
SOURCE
void
unloadcap(planet *p, double x)
{
p->cap += x;
convertcap(p);
}
NAME
unloadcol -- unload colonists.
FUNCTION
Unload colonists unto a planet defrost them and turn
them into population.
SOURCE
void
unloadcol(planet *p, double x, player *P)
{
double y;
x *= POPPERCOL;
y = p->size - p->pop;
if (y > x)
y = x;
p->pop += y;
x -= y;
p->col += x / POPPERCOL;
if (!p->owner)
p->owner = P;
convertcap(p);
}
NAME
unloadgroup --
SYNOPSIS
void unloadgroup(group *g, player *P, double amount)
FUNCTION
SOURCE
void
unloadgroup(group *g, player *P, double amount)
{
double x;
planet *p;
x = amount * g->ships;
p = g->where;
switch (g->loadtype) {
case CG_CAP:
unloadcap(p, x);
break;
case CG_MAT:
p->mat += x;
break;
case CG_COL:
unloadcol(p, x, P);
break;
}
g->load -= amount;
if (g->load < AMOUNTMIN) {
g->loadtype = CG_EMPTY;
g->load = 0.0;
}
}
NAME
unloadphase -- unload cargo unto planet
SOURCE
void
unloadphase(game *aGame)
{
planet *p, *p2;
player *cur_player;
group *g;
int i;
pdebug(DFULL, "Unload Phase\n");
/* Auto Unload */
for (p = aGame->planets; p; p = p->next) {
for (cur_player = aGame->players;
cur_player;
cur_player = cur_player->next) {
if (cur_player->flags & F_AUTOUNLOAD) {
for (g = cur_player->groups; g; g = g->next) {
if (g->where == p && g->dist == 0 && g->ships) {
if ((p->owner && p->owner == cur_player) ||
!p->owner) {
unloadgroup(g, cur_player, g->load);
}
}
}
}
}
}
/* Routes */
for (p = aGame->planets; p; p = p->next) {
if (p->owner) {
for (i = 0; i != CG_EMPTY; i++) {
p2 = p->routes[i];
for (g = p->owner->groups; g; g = g->next) {
if (g->where == p2 &&
g->dist == 0 &&
g->loadtype == i &&
g->ships) {
unloadgroup(g, p->owner, g->load);
}
}
}
}
}
}