view src/snakemove.c @ 6:8c6d5731234d

First entry of Paradise Server 2.9 patch 10 Beta
author darius
date Sat, 06 Dec 1997 04:37:04 +0000
parents
children
line wrap: on
line source

/*--------------------------------------------------------------------------
NETREK II -- Paradise

Permission to use, copy, modify, and distribute this software and its
documentation, or any derivative works thereof, for any NON-COMMERCIAL
purpose and without fee is hereby granted, provided that this copyright
notice appear in all copies.  No representations are made about the
suitability of this software for any purpose.  This software is provided
"as is" without express or implied warranty.

    Xtrek Copyright 1986                            Chris Guthrie
    Netrek (Xtrek II) Copyright 1989                Kevin P. Smith
                                                    Scott Silvey
    Paradise II (Netrek II) Copyright 1993          Larry Denys
                                                    Kurt Olsen
                                                    Brandon Gillespie
--------------------------------------------------------------------------*/

#include "config.h"
#include <stdio.h>
#include <signal.h>

#ifdef apollo
#include <limits.h>
#define MAXINT INT_MAX
#else
#include <values.h>
#endif

#include <math.h>
#include <time.h>
#include "defs.h"
#include "struct.h"
#include "data.h"
#include "planets.h"
#include "shmem.h"

#define SYSWIDTH      (GWIDTH/5)/* width of a system */

/* distance on either side of center */
#define EYEWIDTH		100	/* 100 */
/* which torp the eyes are positioned alongside */
#define EYETORP			0	/* 0 */
/* angle from EYETORP */
#define EYEANGLE		64	/* 64 */
#define TORPSEP			WARP1*12
#define PLANRAD  900
#define PLANRATE 16

/* threshold to avoid galactic boundaries */
#define MD		4500
/* overlap threshold on team boundaries */
#define TMD		2250

/* how often to check for bombers in cyles (1/10th second) */
#define BOMBCHECK	20

/* how often to check for players in the game in cyles (1/10th second) */
#define PLAYERCHECK	100

#define WARHOSTILE(p)		((((p)->p_swar | (p)->p_hostile)& \
				perfs[0]->p_team) || ((perfs[0]->p_swar | \
				perfs[0]->p_hostile) & (p)->p_team))

#define SNAKETORPDAMAGE		30
#define SNAKEPLASMADAMAGE	100

static struct torp *thead, *eyet, *eyetp;
static int lx, ly;
static struct plasmatorp *fl, *fr;
static int explode, explodetorps, tfuse;

extern struct player *perfs[2];
extern int num_perfs;
extern int debug;
extern int lastm;
extern int tno;
extern int target;
extern int berserk;
extern int patrol;
extern int noSmush;
extern int plan_guard;		/* KAO */
extern int planet1, planet2;	/* KAO */
extern int team1, team2;
extern int length;

static int plan_count = 0;
static int s_clock;
static _move();
static int defenders[ALLTEAM];

struct player *whokilledme();
struct planet *homeworld = 0;
struct planet *homestar = 0;

unsigned char getacourse();
extern void (*r_signal()) ();


struct planet *
star_of(pl)
  struct planet *pl;
{
  int i;
  if (pl->pl_system < 1)
    return 0;

  for (i = 0; i < NUMPLANETS; i++)
  {
    if (!(planets[i].pl_flags & PLSTAR))
      continue;
    if (planets[i].pl_system == pl->pl_system)
      return &planets[i];
  }

  return 0;
}



snakemove()
{
  s_clock++;

  _move();
}

static
_move()
{
  if (!perfs[0] || !perfs[1])
    exitSnake();

  /* keep ghostbuster away */
  perfs[0]->p_ghostbuster = 0;
  perfs[1]->p_ghostbuster = 0;

  if (s_clock == 5)
    startsnake();
  else if (s_clock > 5)
  {
    check_explode();
    if (!explode)
    {
      movesnake();
    }
    else if ((perfs[0]->p_ntorp == 0 && perfs[1]->p_ntorp == 0 &&
	    perfs[0]->p_nplasmatorp == 0 && perfs[1]->p_nplasmatorp == 0) ||
      /* xx -- sometimes above doesn't work? */
	     s_clock - explode > 56)
      exitSnake();
  }
  return 1;
}

startsnake()
{
  register i, l;
  register struct player *j;
  register struct torp *k;
  struct player *p1 = perfs[0], *p2 = perfs[1];
  int first = 1;
  int px, py;

  for (i = 0; i < NUMPLANETS; i++)
  {
    if (planets[i].pl_flags & PLHOME && planets[i].pl_owner == 1 << tno)
    {
      homeworld = &planets[i];
      break;
    }
    if (!homeworld && planets[i].pl_owner == 1 << tno)
      homeworld = &planets[i];
  }

  if (!homeworld)
  {
    /* ouch */
    homeworld = &planets[lrand48() % NUMPLANETS];
    fprintf(stderr, "snake: My race (%d) has no planets.  Picking one at random: %s\n", tno, homeworld->pl_name);
  }
  homestar = star_of(homeworld);
  if (!homestar)
    homestar = homeworld;

  px = (lrand48() % 10000) - 5000;
  py = (lrand48() % 10000) - 5000;

  p1->p_ntorp = p2->p_ntorp = 0;
  p1->p_nplasmatorp = p2->p_nplasmatorp = 0;

  /* body */

  for (j = perfs[0]; j; j = (j == perfs[1] ? NULL : perfs[1]))
  {

    for (l = 0, i = j->p_no * MAXTORP, k = &torps[i];
	 i < j->p_no * MAXTORP + length; i++, k++, l++)
    {

      if (l == EYETORP && j == perfs[0])
      {
	/* eye location */
	eyet = k;
      }
      if (l == ((EYETORP == 0) ? 1 : (EYETORP - 1)) && j == perfs[0])
      {
	/* perpendicular torp offset */
	eyetp = k;
      }
      /* torps are free here */
      snake_torp(k, i, j);
      /* note: have to be same team for this to work */
      k->t_x = homeworld->pl_x + px;
      k->t_y = homeworld->pl_y + py - (l + (j == perfs[1] ? length : 0)) * TORPSEP;
      /*
       * if(debug) fprintf(stderr, "k->t_x %d, k->t_y %d\n", k->t_x, k->t_y);
       */
      if (first)
      {
	thead = k;
	first = 0;
      }
    }
  }

  /* eyes */
  fl = &plasmatorps[perfs[0]->p_no * MAXPLASMA];
  fl->pt_no = perfs[0]->p_no * MAXPLASMA;
  fl->pt_status = PTMOVE;
  fl->pt_owner = perfs[0]->p_no;
  fl->pt_team = perfs[0]->p_team;
  fl->pt_x = eyet->t_x - EYEWIDTH;
  fl->pt_y = eyet->t_y;
  if (plan_guard == 0)
    fl->pt_damage = SNAKEPLASMADAMAGE;
  else
    fl->pt_damage = SNAKEPLASMADAMAGE * 10;
  fl->pt_speed = 0;
  fl->pt_war = 0;
  fl->pt_fuse = MAXINT;
  fl->pt_turns = 0;

  perfs[0]->p_nplasmatorp++;

  fr = &plasmatorps[perfs[1]->p_no * MAXPLASMA];
  fr->pt_no = perfs[1]->p_no * MAXPLASMA;
  fr->pt_status = PTMOVE;
  fr->pt_owner = perfs[1]->p_no;
  fr->pt_team = perfs[1]->p_team;	/* doesn't work */
  fr->pt_x = eyet->t_x + EYEWIDTH;
  fr->pt_y = eyet->t_y;
  fr->pt_damage = SNAKEPLASMADAMAGE;
  fr->pt_speed = 0;
  fr->pt_war = 0;
  fr->pt_fuse = MAXINT;
  fr->pt_turns = 0;

  perfs[1]->p_nplasmatorp++;

  if (debug)
    fprintf(stderr, "started\n");
}

restore_eye()
{
  if (fl->pt_status != PTMOVE)
  {
    /* eyes */
    fl = &plasmatorps[perfs[0]->p_no * MAXPLASMA];
    fl->pt_no = perfs[0]->p_no * MAXPLASMA;
    fl->pt_status = PTMOVE;
    fl->pt_owner = perfs[0]->p_no;
    fl->pt_team = perfs[0]->p_team;
    fl->pt_x = eyet->t_x - EYEWIDTH;
    fl->pt_y = eyet->t_y;
    if (plan_guard == 0)
      fl->pt_damage = SNAKEPLASMADAMAGE;
    else
      fl->pt_damage = SNAKEPLASMADAMAGE * 10;
    fl->pt_speed = 0;
    fl->pt_war = 0;
    fl->pt_fuse = MAXINT;
    fl->pt_turns = 0;
    perfs[0]->p_nplasmatorp++;
  }
  if (fr->pt_status != PTMOVE)
  {
    fr = &plasmatorps[perfs[1]->p_no * MAXPLASMA];
    fr->pt_no = perfs[1]->p_no * MAXPLASMA;
    fr->pt_status = PTMOVE;
    fr->pt_owner = perfs[1]->p_no;
    fr->pt_team = perfs[1]->p_team;	/* doesn't work */
    fr->pt_x = eyet->t_x + EYEWIDTH;
    fr->pt_y = eyet->t_y;
    fr->pt_damage = SNAKEPLASMADAMAGE;
    fr->pt_speed = 0;
    fr->pt_war = 0;
    fr->pt_fuse = MAXINT;
    fr->pt_turns = 0;
    perfs[1]->p_nplasmatorp++;
  }
}

movesnake()
{
  register i, px, py;
  register struct player *j;
  register struct torp *k /* , *prev = thead */ ;
  unsigned char tc;
  struct player *tr;
  static
  int dir = 8;
  int ok;

  if ((s_clock % PLAYERCHECK) == 0)
  {
    /* every x seconds make sure there's people in the game */
    ok = 0;
    defenders[FED] = defenders[ROM] = defenders[KLI] = defenders[ORI] = 0;
    for (i = 0, j = players; i < MAXPLAYER; i++, j++)
    {
      if ((j->p_status != PFREE) && !(j->p_flags & PFROBOT))
      {
	ok = 1;
	defenders[j->p_team]++;
      }
    }
    if (!ok)
      exitSnake();
  }
  if (patrol && (target == -1) && (s_clock % BOMBCHECK) == 0)
  {
    target = bombcheck(team1, team2);
  }
  if ((s_clock % (4 + (lrand48() % 4))) == 0)
    dir = -dir;

  thead->t_dir += dir + rrnd(8);

  if (target > -1)
  {
    tr = &players[target];
    if (tr->p_status == PALIVE)
    {
      int nd, td;
      tc = getacourse(tr->p_x, tr->p_y, thead->t_x, thead->t_y);
      nd = angdist(thead->t_dir, tc);
      if (nd > 8)
      {
	td = tc + nd;
	if (td == thead->t_dir)
	  thead->t_dir -= 8;
	else
	  thead->t_dir += 8;
      }
    }
  }
  if (target == -1)
  {
    if (!patrol)
      check_tboundary(ALLTEAM, &thead->t_dir, 8, thead->t_x, thead->t_y);
    else
      check_tboundary(team1 | team2, &thead->t_dir, 8, thead->t_x, thead->t_y);
  }
  lx = thead->t_x;
  ly = thead->t_y;

  if (!plan_guard)
  {
    /* NOTE: we aren't letting the daemon move the torp head */
    thead->t_x += (double) TORPSEP *Cos[thead->t_dir];
    thead->t_y += (double) TORPSEP *Sin[thead->t_dir];
  }
  for (j = perfs[0]; j; j = (j == perfs[1] ? NULL : perfs[1]))
  {
    if (plan_guard)
    {
      int temp;
      thead = &torps[j->p_no * MAXTORP];
      if (j == perfs[0])
	temp = planet1;
      else
	temp = planet2;
      lx = thead->t_x;
      ly = thead->t_y;
      thead->t_x = planets[temp].pl_x + Cos[255 - plan_count] * PLANRAD;
      thead->t_y = planets[temp].pl_y + Sin[255 - plan_count] * PLANRAD;
    }
    for (i = j->p_no * MAXTORP, k = &torps[i];
	 i < j->p_no * MAXTORP + length; i++, k++)
    {

      if (k->t_status == TFREE)
	/* got exploded.  x & y location will remain however */
	snake_torp(k, i, j);

      if (k == thead)
	continue;

      px = k->t_x;
      py = k->t_y;

      k->t_x = lx;
      k->t_y = ly;

      lx = px;
      ly = py;
    }
  }
  if (plan_guard)
  {
    thead = &torps[perfs[0]->p_no * MAXTORP];
    plan_count = (plan_count + PLANRATE) % 256;
  }
  lx = thead->t_x;
  ly = thead->t_y;
  doeyes();
}

check_explode()
{
  register int i, l;
  register struct player *j;
  register struct torp *k;
  static struct player *killer;

  if (fl->pt_status == PTDET || fr->pt_status == PTDET ||
      fl->pt_status == PTEXPLODE || fr->pt_status == PTEXPLODE || explode)
  {
    if (plan_guard)
    {
      restore_eye();
      return;
    }				/* KAO */
    if (debug)
      fprintf(stderr, "snake exploding\n");
    if (!explode)
    {
      /* do once */
      explode = s_clock;
      tfuse = 0;
      if (fl->pt_status == PTDET || fl->pt_status == PTEXPLODE)
      {
	killer = whokilledme(fl);
	if (killer)
	  award(killer);
      }
      if (fr->pt_status == PTDET || fr->pt_status == PTEXPLODE)
      {
	killer = whokilledme(fr);
	if (killer)
	  award(killer);
      }
    }
    if (fl->pt_status != PTFREE && fl->pt_status != PTEXPLODE)
    {
      fl->pt_war = FED | ROM | KLI | ORI;	/* make sure its at war when
						 * it explodes */
      fl->pt_status = PTEXPLODE;
      fl->pt_fuse = 10;
    }
    if (fl->pt_status != PTFREE && fr->pt_status != PTEXPLODE)
    {
      fl->pt_war = FED | ROM | KLI | ORI;
      fr->pt_status = PTEXPLODE;
      fr->pt_fuse = 10;
    }
    /*
     * now for some fancy stuff. If killer is our target and is hostile or at
     * war with our team then snake torp head makes a beeline for him.  This
     * lasts until killer dies or torps have been chasing killer for 40
     * cycles
     */

    if (killer && WARHOSTILE(killer) && (noSmush < 1) && (killer->p_status == PALIVE) &&
	tfuse < 40 && (killer->p_no == target || noSmush < 0))
    {
      crash_killer(killer);
    }
    else
    {
      /* explode all torps in sequence, 1 per cycle until all gone */
      for (j = perfs[0]; j; j = (j == perfs[1] ? NULL : perfs[1]))
      {
	for (l = (j == perfs[0]) ? 0 : length, i = j->p_no * MAXTORP, k = &torps[i];
	     i < j->p_no * MAXTORP + length; i++, k++, l++)
	{
	  if (l == explodetorps && k->t_status != TEXPLODE &&
	      k->t_status != TFREE)
	  {
	    k->t_status = TEXPLODE;
	    k->t_fuse = 10;
	    explodetorps++;
	    return;
	  }
	  else if (l == explodetorps)
	    explodetorps++;
	}
      }
    }
  }
}

crash_killer(p)
  struct player *p;
{
  register int i, px, py;
  register struct player *j;
  register struct torp *k;
  unsigned char tc;
  int active = 0;

  tfuse++;

  tc = getacourse(p->p_x, p->p_y, thead->t_x, thead->t_y);
  thead->t_dir = tc;

  lx = thead->t_x;
  ly = thead->t_y;

  thead->t_x += (double) (12 * WARP1) * Cos[thead->t_dir];
  thead->t_y += (double) (12 * WARP1) * Sin[thead->t_dir];

  for (j = perfs[0]; j; j = (j == perfs[1] ? NULL : perfs[1]))
  {
    for (i = j->p_no * MAXTORP, k = &torps[i];
	 i < j->p_no * MAXTORP + length; i++, k++)
    {

      /* move the head up if it exploded */
      if (k != thead && thead->t_status == TFREE)
	thead = k;
      else if (k == thead)
	continue;

      if (k->t_status != TFREE)
	active++;

      px = k->t_x;
      py = k->t_y;

      k->t_x = lx;
      k->t_y = ly;

      lx = px;
      ly = py;
    }
  }
  return active;
}


doeyes()
{
  unsigned char c = getacourse(eyetp->t_x, eyetp->t_y, eyet->t_x,
			       eyet->t_y);
  int ew = EYEWIDTH, war_ok;

  /* c + 64 -- fl c - 64 -- fr */

  if (plan_guard)
  {
    fl->pt_x = planets[planet1].pl_x + Cos[255 - plan_count] * PLANRAD;
    fl->pt_y = planets[planet1].pl_y + Sin[255 - plan_count] * PLANRAD;
    fr->pt_x = planets[planet2].pl_x + Cos[255 - plan_count] * PLANRAD;
    fr->pt_y = planets[planet2].pl_y + Sin[255 - plan_count] * PLANRAD;
    return;
  }
  if (fl->pt_war)
    ew += 15;

  fl->pt_x = eyet->t_x + (double) (ew) * Cos[(unsigned char) (c - EYEANGLE)];
  fl->pt_y = eyet->t_y + (double) (ew) * Sin[(unsigned char) (c - EYEANGLE)];

#ifdef nodef
  if (fl->pt_x < 0)
    fl->pt_x = 0;
  else if (fl->pt_x > GWIDTH)
    fl->pt_x = GWIDTH;

  if (fl->pt_y < 0)
    fl->pt_y = 0;
  else if (fl->pt_y > GWIDTH)
    fl->pt_y = GWIDTH;
#endif

  if (fr->pt_war)
    ew += 15;

  fr->pt_x = eyet->t_x + (double) (ew) * Cos[(unsigned char) (c + EYEANGLE)];
  fr->pt_y = eyet->t_y + (double) (ew) * Sin[(unsigned char) (c + EYEANGLE)];

#ifdef nodef
  if (fr->pt_x < 0)
    fr->pt_x = 0;
  else if (fl->pt_x > GWIDTH)
    fr->pt_x = GWIDTH;

  if (fr->pt_y < 0)
    fr->pt_y = 0;
  else if (fl->pt_y > GWIDTH)
    fr->pt_y = GWIDTH;
#endif

  /* toggle war */
  if ((s_clock % 6) == 0)
  {
    /*
     * your home planet and shipyards are always safe from your own snake
     * unless you are a target.
     */
    war_ok = !sp_area(thead->t_x, thead->t_y);

    if (!fr->pt_war && war_ok)
      fr->pt_war = (FED | ROM | KLI | ORI) & ~(war_ok ? 0 : (1 << tno));
    else
      fr->pt_war = 0;

    if (!fl->pt_war && war_ok)
      fl->pt_war = (FED | ROM | KLI | ORI) & ~(war_ok ? 0 : (1 << tno));
    else
      fl->pt_war = 0;
  }
}

exitSnake(sig)
  int sig;
{
  register int i;
  register struct player *j;
  register struct torp *k;
  register struct plasmatorp *f;

  r_signal(SIGALRM, SIG_DFL);

  if (debug)
    fprintf(stderr, "snake exiting\n");

  for (j = perfs[0]; j; j = (j == perfs[1] ? NULL : perfs[1]))
  {
    for (i = j->p_no * MAXTORP, k = &torps[i];
	 i < j->p_no * MAXTORP + length; i++, k++)
    {
      /* torps are free here */
      if (k->t_status != TFREE)
	k->t_status = TOFF;
    }
    f = &plasmatorps[j->p_no * MAXPLASMA];
    f->pt_status = PTFREE;
    /* plasma */
  }

  memset(perfs[0], 0, sizeof(struct player));
  memset(perfs[1], 0, sizeof(struct player));
  perfs[0]->p_stats.st_tticks = 1;
  perfs[1]->p_stats.st_tticks = 1;

  /*
   * note: if we had a segmentation violation or bus error we want a core
   * file to debug
   */
  if (sig == SIGBUS || sig == SIGSEGV)
    abort();
  else
    exit(0);
}

pmessage(str, recip, group, address)
  char *str;
  int recip;
  int group;
  char *address;
{
  pmessage2(str, recip, group, address, 255);
}

pmessage2(str, recip, group, address, from)
  char *str;
  int recip;
  int group;
  char *address;
  unsigned char from;
{
  struct message *cur;
  int mesgnum;

  if ((mesgnum = ++(mctl->mc_current)) >= MAXMESSAGE)
  {
    mctl->mc_current = 0;
    mesgnum = 0;
  }
  cur = &messages[mesgnum];
  cur->m_no = mesgnum;
  cur->m_flags = group;
  cur->m_recpt = recip;
  cur->m_from = from;
  (void) sprintf(cur->m_data, "%-9s %s", address, str);
  cur->m_flags |= MVALID;
}

/* get course from (mx,my) to (x,y) */
unsigned char
getacourse(x, y, mx, my)
  int x, y, mx, my;
{
  if (x == mx && y == my)
    return 0;

  return (unsigned char) (int) (atan2((double) (x - mx),
				      (double) (my - y)) / 3.14159 * 128.);
}

/*
 * FED 1 ROM 2 KLI 4 ORI 8
 */

/*
 * 256/0 192  +   64 128 */

check_tboundary(teams, mycrs, range, x, y)
  int teams;
  int x, y;
  unsigned char *mycrs;
  int range;
{
  int lx = homestar->pl_x - SYSWIDTH / 2, rx = homestar->pl_x + SYSWIDTH / 2,
      ty = homestar->pl_y - SYSWIDTH / 2, by = homestar->pl_y + SYSWIDTH / 2;
  int r = 0, l = 0;
  unsigned char crs = *mycrs;

  if (x < lx && crs >= 128)
  {
    if (crs >= 192)
      *mycrs += range;
    else
      *mycrs -= range;
    l = 1;
  }
  else if (x > rx && crs < 128)
  {
    if (crs > 64)
      *mycrs += range;
    else
      *mycrs -= range;
    r = 1;
  }
  if (y < ty && (crs >= 192 || crs < 64))
  {
    if (crs >= 192 && !l)
      *mycrs -= range;
    else
      *mycrs += range;
  }
  else if (y > by && (crs < 192 && crs >= 64))
  {
    if (crs < 128 && !r)
      *mycrs -= range;
    else
      *mycrs += range;
  }
}

/* return rnd between -range & range */
rrnd(range)
  int range;
{
  return lrand48() % (2 * range) - range;
}

#ifdef nodef
/* NOTUSED */
contrast(t)
  int t;
{
  return ROM;			/* experiment */
  switch (t)
  {
   case FED:
    return ORI;
   case ORI:
    return FED;
   case KLI:
    return ROM;
   case ROM:
    return KLI;
   default:
    return FED;
  }
}

#endif

snake_torp(t, n, p)
  struct torp *t;
  int n;
  struct player *p;
{
  t->t_no = n;
  t->t_status = TMOVE;
  t->t_owner = p->p_no;
  t->t_team = p->p_team;
  t->t_dir = 128;
  if (plan_guard == 0)
    t->t_damage = SNAKETORPDAMAGE;
  else
    t->t_damage = SNAKETORPDAMAGE * 10;
  t->t_speed = 0;
  if (berserk)
    t->t_war = FED | ROM | ORI | KLI;
  else if (target == -1)
    t->t_war = 0;
  else
    t->t_war = perfs[0]->p_swar | perfs[0]->p_hostile;
  t->t_fuse = MAXINT;
  t->t_turns = 0;
  p->p_ntorp++;
}

struct player *
whokilledme(pt)
  struct plasmatorp *pt;
{
  register i;
  register struct phaser *j;

  for (i = 0, j = &phasers[i]; i < MAXPLAYER; i++, j++)
  {
    if (j->ph_status == PHHIT2)
    {
      if (debug)
      {
	fprintf(stderr, "found PHHIT2 from %d at %d,%d\n", players[i].p_no,
		j->ph_x, j->ph_y);
	fprintf(stderr, "plasma is at %d,%d\n", pt->pt_x, pt->pt_y);
	fprintf(stderr, "fl is at %d,%d\n", fl->pt_x, fl->pt_y);
	fprintf(stderr, "fr is at %d,%d\n", fr->pt_x, fr->pt_y);
      }
      if (j->ph_x == pt->pt_x && j->ph_y == pt->pt_y)
      {
	return &players[i];
      }
    }
  }
  return NULL;
}

/*
 * NOTE: the procedure could be writing shared memory variables at the same
 * time as the daemon.  This may produce unpredicatable results.  A better
 * implementation would mark the "snake plasma" and have the daemon do the
 * awarding.
 */

award(win)
  struct player *win;
{
  char buf[80];
  char addrbuf[10];

  if (!win)
    return;

  if (target == -1 && !(win->p_flags & PFROBOT) && !WARHOSTILE(win))
  {
    strcpy(buf, "Snake eyes!");

    /* what do we have for our big winner today, fred? */

    if (((100 * win->p_damage) / win->p_ship.s_maxdamage) > 50 ||
	((100 * win->p_shield) / win->p_ship.s_maxshield) < 50)
    {
      win->p_damage = 0;
      win->p_shield = win->p_ship.s_maxshield;
      strcat(buf, " You win free repairs!");
    }
    else if (((100 * win->p_fuel) / win->p_ship.s_maxfuel) < 50)
    {
      win->p_fuel = win->p_ship.s_maxfuel;
      strcat(buf, " You win free fuel!");
    }
    else if (((100 * win->p_etemp) / win->p_ship.s_maxegntemp) > 60)
    {
      win->p_etemp = 0;
      strcat(buf, " You win free engine cooling!");
    }
    else if (((100 * win->p_wtemp) / win->p_ship.s_maxwpntemp) > 60)
    {
      win->p_wtemp = 0;
      strcat(buf, " You win free weapons cooling!");
    }
    else
    {
      win->p_damage = 0;
      win->p_shield = win->p_ship.s_maxshield;
      win->p_fuel = win->p_ship.s_maxfuel;
      win->p_etemp = 0;
      win->p_wtemp = 0;
      strcat(buf, " You feel healthy!");
    }

    /* ... */

    sprintf(addrbuf, "%s->%c%c", SERVNAME,
	    teams[win->p_team].letter, shipnos[win->p_no]);
    pmessage2(buf, win->p_no, MINDIV, addrbuf, 255);
  }
  sprintf(buf, "%s (%c%c) slew the vile space serpent!",
	  win->p_name, teams[win->p_team].letter, shipnos[win->p_no]);
  pmessage(buf, 0, MALL | MKILLA, MSERVA, 255);

  /* and get .5 kills */

  win->p_kills += 0.5;
  if (win->p_ship.s_type == STARBASE)
  {
    if (win->p_stats.st_sbmaxkills < win->p_kills)
    {
      win->p_stats.st_sbmaxkills = win->p_kills;
    }
  }
  else if (win->p_stats.st_tmaxkills < win->p_kills)
  {
    win->p_stats.st_tmaxkills = win->p_kills;
  }
}

bombcheck(team1, team2)
  int team1, team2;
{
  register i;
  register struct player *j;
  struct planet *p;

  for (i = 0, j = players; i < MAXPLAYER; i++, j++)
  {
    if (j->p_status == PALIVE)
    {
      if ((j->p_flags & PFBOMB) && (j->p_flags & PFORBIT))
      {
	p = &planets[j->p_planet];
	if (!((j->p_swar | j->p_hostile) & p->pl_owner))
	  continue;

	if (defenders[p->pl_owner] >= configvals->tournplayers)
	  continue;

#if 0
	/* ignore planets that aren't within team boundaries */
	if (p->pl_x > boundaries[p->pl_owner].rx ||
	    p->pl_x < boundaries[p->pl_owner].lx ||
	    p->pl_y > boundaries[p->pl_owner].by ||
	    p->pl_y < boundaries[p->pl_owner].ty)
	  continue;
#endif

	if (!team1 && !team2)
	{
	  /* any planet */
	  printf("snake found bomber: targeting %c%c\n",
		 teams[j->p_team].letter, shipnos[j->p_no]);
	  fflush(stdout);
	  make_war(j, p->pl_owner);
	  return j->p_no;
	}
	else
	{
	  if (team1)
	  {
	    if (p->pl_owner == team1)
	    {
	      printf("found bomber: targeting %c%c\n",
		     teams[j->p_team].letter, shipnos[j->p_no]);
	      fflush(stdout);
	      make_war(j, p->pl_owner);
	      return j->p_no;
	    }
	  }
	  if (team2)
	  {
	    if (p->pl_owner == team2)
	    {
	      printf("found bomber: targeting %c%c\n",
		     teams[j->p_team].letter, shipnos[j->p_no]);
	      fflush(stdout);
	      make_war(j, p->pl_owner);
	      return j->p_no;
	    }
	  }
	}
      }
    }
  }
  return -1;
}

make_war(p, plteam)
  struct player *p;
  int plteam;
{
  register int i;
  register struct player *j;
  register struct torp *k;

  perfs[0]->p_team = plteam;
  perfs[0]->p_swar = 0;
  perfs[0]->p_hostile = 0;
  perfs[1]->p_team = plteam;
  perfs[1]->p_swar = 0;
  perfs[1]->p_hostile = 0;

  perfs[0]->p_swar |= p->p_team;
  perfs[0]->p_hostile |= p->p_team;
  perfs[1]->p_swar |= p->p_team;
  perfs[1]->p_hostile |= p->p_team;

  /* update our torps war status */
  for (j = perfs[0]; j; j = (j == perfs[1] ? NULL : perfs[1]))
  {
    for (i = j->p_no * MAXTORP, k = &torps[i];
	 i < j->p_no * MAXTORP + length; i++, k++)
    {

      k->t_war = perfs[0]->p_swar | perfs[0]->p_hostile;
    }
  }
}



/*
 * start planet areas are places where people will likely enter the game
 * (only considers 1 start planet at this time)
 */

sp_area(x, y)
  int x, y;
{
  register i, j, px, py;

#if 0
  /* check for proximity to a shipyard? */
  return 0;
#else

  for (i = 0; i < NUMPLANETS; i++)
  {
    struct planet *pl = &planets[i];
    if (!(pl->pl_flags & (PLSHIPYARD | PLHOME)))
      continue;
    px = pl->pl_x;
    py = pl->pl_y;
    /* printf("checking %s (%d,%d)\n", pl->pl_name, i*10,j); */

    if (!(x < px - 5300 || x > px + 5300 ||
	  y < py - 5300 || y > py + 5300))
    {
#ifdef maybe			/* not used. */
      if (target != -1)
      {
	struct player *p = &players[target];
	/*
	 * if target is also in same home area, he should at least be able to
	 * phaser the snake since the torps are already deadly
	 */
	if (!(p->p_x < px - 5300 || p->p_x > px + 5300 ||
	      p->p_y < py - 5300 || p->p_y > py + 5300))
	  return 0;
	else
	  return 1;
      }
#endif
      return 1;
    }
  }

  return 0;

#endif
}