[comp.sources.games.bugs] <None>

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 */
	}
  }
 
 }

}