vancleef@ohstpy.mps.ohio-state.edu (06/23/89)
it is VERY IMPORTANT that you replace doship.c with this version of it
in your GB code. it contains a very important self check for the
daemon to weed out an exotic bug in the program!
Garrett
/*
* Galactic Bloodshed (Robert Chansky, smq@b)
* doship -- do one ship turn.
*/
#include "vars.h"
#include "ships.h"
#include "races.h"
#include "doturn.h"
#include "power.h"
#include <math.h>
#include <strings.h>
extern struct power Power[];
doship(shipno,ship)
int shipno;
shiptype *ship;
{
int sh,sh2,j,shfdata;
char buf[300];
if (!ship->is_dead && ship->owner == 0){
ship->is_dead=1;
} /* used to counteract bugs */
if (!ship->is_dead) {
/* add ships, popn to total count to add AP's */
if (ship->type==OTYPE_VN)
Power[ship->owner].ships_owned += ship->orders.object.number;
else
Power[ship->owner].ships_owned++;
Power[ship->owner].resource += ship->resource;
Power[ship->owner].fuel += ship->fuel;
Power[ship->owner].destruct += ship->destruct;
Power[ship->owner].popn += ship->popn;
if (ship->whatorbits==LEVEL_UNIV) {
Sdatanumships[ship->owner]++;
Sdatapopns[ship->owner] += ship->popn;
} else {
starnumships[ship->storbits][ship->owner] +=
(ship->type==OTYPE_VN) ? ship->orders.object.number : 1;
/* add popn of ships to popn */
starpopns[ship->storbits][ship->owner] += ship->popn;
/* set inhabited for ship */
setbit(Stars[ship->storbits]->inhabited, ship->owner);
}
/* repair radiation */
if (ship->rad) {
/* kill off some people */
ship->popn = round_rand(ship->popn * .90);
if (ship->rad > REPAIR_RATE)
ship->rad -= REPAIR_RATE;
else
ship->rad = 0;
} else {
/* irradiated ships are immobile.. */
/* make sure of an update if someones bombarding the planet */
if (can_bombard(ship) && ship->orders.o.bombard &&
ship->whatorbits==LEVEL_PLAN)
Stinfo[ship->storbits][ship->pnumorbits].inhab = 1;
Moveship(shipno, ship);
/* repair ship by the amount of crew it has */
if (ship->damage && ship->popn) { reg int d;
if ((d = ((float)ship->popn /
Shipdata[ship->type][ABIL_MAXCREW]) * REPAIR_RATE)
> ship->damage)
ship->damage = 0;
else
ship->damage -= d;
}
switch (ship->type) {
case OTYPE_CANIST:
if (ship->whatorbits == LEVEL_PLAN && !ship->is_docked) { short *t;
if (--ship->orders.object.number) {
t = &Stinfo[ship->storbits][ship->pnumorbits].temp_add;
if (*t - 10 < -120)
*t = -120;
else
*t -= 10;
} else { /* timer expired; destroy canister */
reg int j=0;
kill_ship(ship);
teleg_add("",telegram_buf);
sprintf(buf,"Notice from /%s/%s\n\n",
Stars[ship->storbits]->name,
Stars[ship->storbits]->pnames[ship->pnumorbits]);
teleg_add(buf,telegram_buf);
teleg_add("Canister of dust previously covering this planet has dissipated.\n",telegram_buf);
for (j=1; j<=Num_races; j++)
if (planets[ship->storbits][ship->pnumorbits]->info[j-1].numsectsowned)
teleg_send(TELEG_PLAYER_AUTO, j, telegram_buf);
}
}
break;
case STYPE_MINE:
/* check around and see if we should explode. */
if (ship->on) {
int rad=0; float xd,yd; int p;
if (ship->whatorbits==LEVEL_STAR)
sh = Stars[ship->storbits]->ships;
else if (ship->whatorbits==LEVEL_PLAN)
sh = planets[ship->storbits][ship->pnumorbits]->ships;
else
sh = 0; /* don't explode in interstellar space. so what. */
sh2 = sh;
/* traverse the list, look for people we are at war with,
and are closer than the trigger radius... */
while (sh) {
xd = ships[sh]->xpos - ship->xpos;
yd = ships[sh]->ypos - ship->ypos;
if (isset(races[ship->owner]->atwar,ships[sh]->owner) &&
(abs(xd)+abs(yd)) < ship->orders.object.number)
rad = 1;
sh = ships[sh]->nextship;
}
if (rad) {
/* we've found someone we don't like,
detonate and irradiate them */
kill_ship(ship);
teleg_add("",telegram_buf);
sprintf(buf, "BULLETIN!\n mine #%d triggered at system /%s",shipno,Stars[ship->storbits]->name);
teleg_add(buf, telegram_buf);
teleg_send(TELEG_PLAYER_AUTO,ship->owner,telegram_buf);
while (sh2) { /* sh2=beginning of list */
xd = ships[sh2]->xpos - ship->xpos;
yd = ships[sh2]->ypos - ship->ypos;
if (sh2!=shipno &&
(abs(xd)+abs(yd)) < ship->orders.object.number) {
rad = round_rand(((float)Shipdata[STYPE_MINE][ABIL_DESTCAP] / ship->destruct)*.5);
if (ships[sh2]->rad + rad > 100)
ships[sh2]->rad = 100;
else
ships[sh2]->rad += rad;
teleg_add("",telegram_buf);
sprintf(buf, "BULLETIN!\n ship #%d irradiated by mine at system /%s", sh2, Stars[ship->storbits]->name);
teleg_add(buf, telegram_buf);
teleg_send(TELEG_PLAYER_AUTO,ships[sh2]->owner,telegram_buf);
}
sh2 = ships[sh2]->nextship;
}
}
}
break;
case STYPE_MIRROR:
switch (ship->orders.aimed_at.level) {
case LEVEL_SHIP: /* ship aimed at is a legal ship now */
/* if in the same system */
if ( (ship->whatorbits==LEVEL_STAR || ship->whatorbits==LEVEL_PLAN)
&& (ships[ship->orders.aimed_at.shipno]!=NULL)
&& (ships[ship->orders.aimed_at.shipno]->whatorbits==LEVEL_STAR ||
ships[ship->orders.aimed_at.shipno]->whatorbits==LEVEL_PLAN)
&& ship->storbits == ships[ship->orders.aimed_at.shipno]->storbits
&& !ships[ship->orders.aimed_at.shipno]->is_dead )
ships[ship->orders.aimed_at.shipno]->damage += 10;
break;
case LEVEL_PLAN: { reg short *t; reg int i;
t = &Stinfo[ship->storbits][ship->orders.aimed_at.pnum].temp_add;
i = ship->orders.aimed_at.intensity;
if (*t + i > 120)
*t = 120;
else if (*t + i < -120)
*t = -120;
else
*t += i;
}
break;
case LEVEL_STAR:
if (ship->orders.aimed_at.snum>0 &&
ship->orders.aimed_at.snum<Sdata.numstars)
Stars[ship->orders.aimed_at.snum]->stability += random()&01;
break;
case LEVEL_UNIV:
break;
}
break;
case STYPE_GOD:
/* gods have infinite power.... heh heh heh */
ship->fuel = Shipdata[ship->type][ABIL_FUELCAP];
ship->popn = Shipdata[ship->type][ABIL_MAXCREW];
ship->destruct = Shipdata[ship->type][ABIL_DESTCAP];
ship->resource = Shipdata[ship->type][ABIL_CARGO];
break;
case OTYPE_AP: /* terraforming device */
/* if landed on planet, change conditions to be like race */
if (ship->is_docked && ship->whatdest==LEVEL_PLAN && ship->on) {
int j,d,a;planettype *p;
p = planets[ship->storbits][ship->pnumorbits];
if (ship->fuel >= 3.0) {
ship->fuel -= 3.0;
for (j=RTEMP+1; j<=OTHER; j++) {
if ( (d = races[ship->owner]->conditions[j] - p->conditions[j]) != 0) {
a = int_rand(sgn(d)*3,-sgn(d));
if (p->conditions[j] + a < 0)
p->conditions[j] = 0;
else if (p->conditions[j] + a > 100)
p->conditions[j] = 100;
else p->conditions[j] += a;
}
}
}
}
break;
case OTYPE_AMOEBA: /* space amoeba */
if (ship->orders.amoeba.dig) {
/* we are currently digesting a planet. */
if (planets[ship->storbits][ship->pnumorbits]->digested) {
reg int i,s; reg bool f=0;
/* the planet has been digested. get rid of it. */
/* move the highest-#'d planet over this one */
/*Stars[ship->storbits]->numplanets--;
Stars[ship->storbits]->planetpos[ship->pnumorbits] =
Stars[ship->storbits]->planetpos[Stars[ship->storbits]->numplanets];
strcpy(Stars[ship->storbits]->pnames[ship->pnumorbits],
Stars[ship->storbits]->pnames[Stars[ship->storbits]->numplanets]);
/* insert into star list */
/*ship->nextship = Stars[ship->storbits]->ships;
Stars[ship->storbits]->ships = shipno;*/
/* kill all ships here; take their stuff */
/*sh = planets[ship->storbits][ship->pnumorbits]->ships;
while (sh) {
if (sh!=shipno) ) {
ship->destruct += ships[sh]->destruct;
ship->mass += ships[sh]->destruct*MASS_DESTRUCT;
ship->fuel += ships[sh]->fuel;
ship->mass += ships[sh]->fuel*MASS_FUEL;
kill_ship(ships[sh]);
}
sh = ships[sh]->nextship;
}
/* no longer orbiting star */
/*ship->whatorbits = LEVEL_STAR;
ship->whatdest = LEVEL_UNIV;*/
/* no longer digesting */
ship->orders.amoeba.dig = 0;
/* find a new place to digest */
ship->orders.amoeba.dest = 0;
}
} else {
/* we have a planet in mind. */
if (!ship->orders.amoeba.dest || ship->whatdest==LEVEL_UNIV) {
/* we have orders; wait to get to destination */
if (ship->whatdest == LEVEL_PLAN &&
ship->whatorbits == LEVEL_PLAN &&
ship->deststar == ship->storbits &&
ship->destpnum == ship->pnumorbits) {
/* we just arrived at our destination. */
Stinfo[ship->storbits][ship->pnumorbits].amoeba_add = 1;
/* start digesting */
ship->orders.amoeba.dig = 1;
/* telegram people */
teleg_add("", telegram_buf);
teleg_add("BULLETIN!!\n\n ",telegram_buf);
sprintf(buf, "%s #%d is attacking your planet /%s/%s!\n\n",
Shipnames[ship->type],
shipno, Stars[ship->storbits]->name,
Stars[ship->storbits]->pnames[ship->pnumorbits]);
teleg_add(buf, telegram_buf);
for (j=1; j<=Num_races; j++)
if (planets[ship->storbits][ship->pnumorbits]->info[j-1].numsectsowned)
teleg_send(TELEG_PLAYER_AUTO, j, telegram_buf);
}
} else {
reg int s,min=0,min2=0,i;
char expl=0,expl2=0;
/* find a yummy planet to munch on */
/* find closest _explored_ star */
/* (this is the opposite method VN's use) */
for (s=0; s<Sdata.numstars; s++)
if (s != ship->storbits &&
Distsq(Stars[s]->xpos,Stars[s]->ypos,ship->xpos,ship->ypos) <
Distsq(Stars[min]->xpos,Stars[min]->ypos,ship->xpos,ship->ypos))
min2 = min,min = s;
for (i=0; i<howmanybytes(Num_races); i++) {
expl |= Stars[min]->inhabited[i];
expl2 |= Stars[min2]->inhabited[i];
}
if (!expl)
if (!expl2)
ship->deststar = int_rand(0,Sdata.numstars-1);
else
ship->deststar = min2; /* 2nd closest star */
else
ship->deststar = min;
/* find a good planet to go to */
if (Stars[ship->deststar]->numplanets) {
ship->destpnum =
int_rand(0,Stars[ship->deststar]->numplanets-1);
ship->whatdest = LEVEL_PLAN;
ship->orders.amoeba.dest = 1;
} else {
/* no good; find someplace else. */
ship->orders.amoeba.dest = 0;
}
ship->speed = 1; /* amoebae are very fastidious,too */
fprintf(stderr,"amoeba #%d headed for star %d, pl %d.\n",shipno,ship->deststar, ship->destpnum);
}
}
break;
case OTYPE_VN: /* Von Neumann machine */
do_VN(ship,shipno);
break;
case STYPE_ASS:
/* "indimidate" the planet below, for enslavement purposes. */
if (ship->whatorbits==LEVEL_PLAN)
Stinfo[ship->storbits][ship->pnumorbits].intimidated = 1;
break;
case OTYPE_OMCL:
/* orbital mind control laser */
if (ship->orders.aimed_at.level==LEVEL_PLAN && ship->on &&
ship->speed==1) {
planets[ship->orders.aimed_at.snum][ship->orders.aimed_at.pnum]
->is_sheep = 1;
}
break;
case STYPE_HABITAT:{ reg int add;
/* habitats multiply some resources inside them. */
add = ship->resource *
((float)ship->popn / Shipdata[STYPE_HABITAT][ABIL_MAXCREW])
* (100 - ship->damage) * 0.001;
if (ship->resource+add > Shipdata[STYPE_HABITAT][ABIL_CARGO])
add = Shipdata[STYPE_HABITAT][ABIL_CARGO] - ship->resource;
ship->resource += add;
ship->mass += add * MASS_RESOURCE;
add = ship->popn * races[ship->owner]->birthrate *
(100 - ship->damage) * 0.005;
if (ship->popn+add > Shipdata[STYPE_HABITAT][ABIL_MAXCREW])
add = Shipdata[STYPE_HABITAT][ABIL_MAXCREW] - ship->popn;
ship->popn += add;
ship->mass += add * races[ship->owner]->mass;
} break;
case STYPE_POD:
if (ship->notified) {
/* we just arrived at this system -- explode */
/* or, we are floating in space with no fuel -- just die */
reg int i,f= -1;
kill_ship(ship);
if (ship->whatorbits==LEVEL_STAR) {
for (i=0; f== -1 && i<Stars[ship->storbits]->numplanets; i++)
if (sqrt((double)Distsq(ship->xpos, ship->ypos,
Stars[ship->storbits]->xpos + planets[ship->storbits][i]->xpos,
Stars[ship->storbits]->ypos + planets[ship->storbits][i]->ypos))/SYSTEMSIZE < float_rand())
f = i;
teleg_add("",telegram_buf);
sprintf(buf, "Bulletin\n\nSpore pod #%d has warmed and exploded.\n",shipno);
teleg_add(buf,telegram_buf);
if (f != -1) {
sprintf(buf,"A spore has landed on planet %s.\n",Stars[ship->storbits]->pnames[f]);
Stinfo[ship->storbits][f].Thing_add = ship->owner;
/* so doplanet does not pass over it */
setbit(Stars[ship->storbits]->inhabited,ship->owner);
planets[ship->storbits][f]->info[ship->owner-1].explored = 1;
} else {
sprintf(buf,"No spores have survived.\n");
}
teleg_add(buf,telegram_buf);
teleg_send(TELEG_PLAYER_AUTO, ship->owner, telegram_buf);
teleg_add("",telegram_buf);
sprintf(buf,"BULLETIN!\n\n A spore pod has exploded in system /%s.\n",Stars[ship->storbits]->name);
teleg_add(buf,telegram_buf);
teleg_add("Spores may have drifted to planets here.\n",telegram_buf);
for (i=1; i<=Num_races; i++)
if (i!=ship->owner && isset(Stars[ship->storbits]->inhabited,i))
teleg_send(TELEG_PLAYER_AUTO, i, telegram_buf);
}
}
break;
default:
break;
}
}
} else if (ship->owner ==0 || !ship->notified) {
/* ship is dead -- add to shipfree file, remove from all lists. */
/* if notified, this means it's already been deleted and written. */
ship->notified = 1;
makeshipdead(shipno);
printf("destroyed ship #%d\n",shipno);
}
}
do_VN(ship,shipno)
shiptype *ship;
int shipno;
{
int r;
planettype *p;
char buf[150];
if (ship->on) {
if (ship->whatorbits==LEVEL_PLAN)
p = planets[ship->storbits][ship->pnumorbits];
if (ship->whatorbits==LEVEL_PLAN &&
ship->is_docked && ship->whatdest==LEVEL_PLAN) {
/* make sure the planet is updated */
Stinfo[ship->storbits][ship->pnumorbits].inhab = 1;
/* try to launch it */
if (ship->orders.object.number2 == 0) { /* launch if no assignment */
/* steal some fuel from other players,telegram */
int f=0;
if (ship->fuel < Shipdata[OTYPE_VN][ABIL_COST]) {
for (r=1; !f && r<=Num_races; r++)
if (p->info[r-1].fuel >= Shipdata[OTYPE_VN][ABIL_COST])
f = r;
if (f) {
ship->fuel += Shipdata[OTYPE_VN][ABIL_FUELCAP];
p->info[f-1].fuel -= Shipdata[OTYPE_VN][ABIL_FUELCAP];
teleg_add("",telegram_buf);
teleg_add("Bulletin!\n\n",telegram_buf);
sprintf(buf,"%d fuel stolen by %s #%d on planet /%s/%s!\n",
Shipdata[OTYPE_VN][ABIL_FUELCAP],
Shipnames[OTYPE_VN],
shipno, Stars[ship->storbits]->name,
Stars[ship->storbits]->pnames[ship->pnumorbits]);
teleg_add(buf,telegram_buf);
teleg_send(TELEG_PLAYER_AUTO, f, telegram_buf);
ship->orders.object.number2 = 0; /* no current assignment */
ship->xpos = Stars[ship->storbits]->xpos + planets[ship->storbits][ship->pnumorbits]->xpos + int_rand(-10,10);
ship->ypos = Stars[ship->storbits]->ypos + planets[ship->storbits][ship->pnumorbits]->ypos + int_rand(-10,10);
ship->is_docked = 0;
ship->whatdest = LEVEL_UNIV;
}
}
} else {
/* we have an assignment. Since we are landed, this means
we are engaged in building up resources/fuel. */
/* steal resources from other players,telegram */
reg int i,f; int nums[MAXPLAYERS+1];
/* permute list of people to steal from */
for (i=1; i<=Num_races; i++)
nums[i] = i;
for (i=1; i<=Num_races; i++) {
f = int_rand(1,Num_races);
swap(nums[i], nums[f]);
}
for (f=0,i=1; i<=Num_races; i++)
if (p->info[nums[i]-1].resource)
f = nums[i];
if (f) {
p->info[f-1].resource -= Shipdata[OTYPE_VN][ABIL_COST];
ship->resource += Shipdata[OTYPE_VN][ABIL_COST];
ship->mass += Shipdata[OTYPE_VN][ABIL_COST] * MASS_RESOURCE;
teleg_add("",telegram_buf);
teleg_add("Bulletin!\n\n",telegram_buf);
sprintf(buf,"%d resources stolen by %s #%d\non planet ",
Shipdata[OTYPE_VN][ABIL_COST],
Shipnames[OTYPE_VN], shipno);
teleg_add(buf,telegram_buf);
sprintf(buf,"/%s/%s!\n",
Stars[ship->storbits]->name,
Stars[ship->storbits]->pnames[ship->pnumorbits]);
teleg_add(buf,telegram_buf);
teleg_send(TELEG_PLAYER_AUTO, f, telegram_buf);
} else {
/*if no resources to steal, more will be produced in doplanet*/
}
}
} else {
/* we are not landed */
if (ship->orders.object.number2) {
/* we've arrived from somewhere -- look for a place to land.
this is done on planet turn */
} else {
/* we were just built & launched */
reg int s,min=0,min2=0;
/* find closest unexplored star */
for (s=1; s<Sdata.numstars; s++)
if (s != ship->storbits &&
Distsq(Stars[s]->xpos,Stars[s]->ypos,ship->xpos,ship->ypos) <
Distsq(Stars[min]->xpos,Stars[min]->ypos,ship->xpos,ship->ypos))
min2 = min,min = s;
/* don't go there if we have a choice,
and we have VN's there already */
if (isset(Stars[min]->inhabited,1))
if (isset(Stars[min2]->inhabited,1))
ship->deststar = int_rand(0,Sdata.numstars-1);
else
ship->deststar = min2; /* 2nd closest star */
else
ship->deststar = min;
if (Stars[ship->deststar]->numplanets) {
ship->destpnum =
int_rand(0,Stars[ship->deststar]->numplanets-1);
ship->whatdest = LEVEL_PLAN;
ship->orders.object.number2 = 1;
} else {
/* no good; find someplace else. */
ship->orders.object.number2 = 0;
}
ship->speed = 1; /* VN's are very fastidious */
fprintf(stderr,"VN #%d headed for star %d, pl %d.\n",shipno,ship->deststar, ship->destpnum);
/* we are assigned to go */
}
}
}
}