/* Marsmove.c
*/

/* Known bugs: 
   get teleported when joining (part of reset_player) 
   -- annoying, but noncritical, i.e. haven't bothered to fix it ;) 
*/

/*
  Based on puckmove.c of 2.01pl5 on 1-7-93 with major modifications
  by Jeff Nelson (jn)

  Modified for use with guzzler code by Michael Kantner (MK)
  Base upon code ftp'd from hobbes.ksu.ksu.edu on 9-9-93
  Please mail all bugs, patches, comments to kantner@hot.caltech.edu

  Updated extensively

  Credits to Terence Chang for writing the initial version of puck
          to Brick Verser for maintaining and improving it
          to numerous others for comments and criticism
*/

#include "copyright.h"

#include <stdio.h>
#include <signal.h>
#include <math.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include "defs.h"
#include "struct.h"
#include "data.h"
#include "marsdefs.h"


/*#define DOGDEBUG              /* debugging compiler option, too much */

#define WEAKER_STR 2		/* integer factor to divide tractstr down */
#define WEAKER_RNG 1.25		/* factor to divide tractrng down */

#define SIZEOF(s)		(sizeof (s) / sizeof (*(s)))
#define AVOID_TIME		4
#define AVOID_CLICKS		200
#define WARFUSE                 5    /* seconds to wait to update war */
#define NORMALIZE(d) 		(((d) + 256) % 256)
#define RANKER(p)		(p->kills + (p->oggs / 2) + (p->mutuals / 4))

#define PU_SITOUT		0x0001
#define PU_FILLER		0x0002

#define PU_DOG			0x1000
#define PU_CONTEST		0x2000
#define PU_WAIT			0x4000
#define PU_DONE			0x8000
#define PU_NOTCONTEST		(PU_SITOUT|PU_DONE|PU_FILLER)  
#define PU_NOTAVAIL		(PU_NOTCONTEST|PU_DOG|PU_WAIT)  

typedef struct DogStat {        /* player record saved to file */
    int d_mutuals;              /* number of tournament mutuals */
    int d_oggs;                 /* number of tournament oggs */
    int d_wins;                 /* number of tournament wins */
    int d_losses;               /* number of tournament losses */
    int d_rating;               /* overall rating */
    int d_timerating;           /* time rating compared to peers */
    int d_ticks;
    int d_pad3;                 /* future expansion */
} DogStat;


typedef struct Track {		/* our record of this player */
    int t_no;                   /* player number */
    int t_x;			/* position at last update */
    int t_y;
    int t_pos;			/* position in player stat file */
    DogStat t_stats;            /* tournament stats structure */
    int t_status;		/* status at last update */
    u_int t_seconds;		/* time in tournament */
    u_int t_flags;		/* MK - new, additional flags */
    char t_arena;		/* arena player is in (0 middle, 1-8 fighting */
    char t_opponent;		/* opponent in dogfight mode */
    float t_score;		/* pretty much an echo of j->p_kills */
    int t_wait;			/* mutual time counter after killing opponent*/
    int t_preferred;		/* player's preferred ship */
    int t_mutuals[MAXPLAYER];	/* mutuals a player has received in tournament*/
    int t_oggs[MAXPLAYER];	/* oggs (worst stat to have, you died first */
    int t_wins[MAXPLAYER];	/* wins with survival */
} Track;


typedef struct DogStatEntry {
    char name[NAME_LEN];
    DogStat dstats;
} DogStatEntry;


typedef struct Arena {          /* record of Arena */
  int a_no;                     /* arena number */
  int a_free;                   /* is arena free? */
  int a_x;                      /* center point of arena */
  int a_y;
  int a_right;                  /* right limit */
  int a_left;                   /* left limit */
  int a_top;                    /* top limit */
  int a_bottom;                 /* bottom limit */
} Arena;

/* Mars specific variables grouped here (mostly) */
Arena arenas[MAXARENAS];
int inprogress = 0;
int toolate2join = 0;
int matchnum = 0;

/*
  The following is included for the sole purpose of making sure
  someone without the minor server mods might just still be
  able to run the robot (without a .sysdef interface though).
*/
#ifndef DOGFIGHT
/* Needed for Mars */
int	nummatch=4;
int	contestsize=2;
int     dogcounts=1;
#endif

Track tracks[MAXPLAYER];

extern char *shiptypes[];
extern char DogStats[256];

/* puck junk */

#define END_OF_PERIOD 20*60*PERSEC
#define PERIODS_PER_GAME 3
#define FACEOFF (30+TELEPORT_DELAY)*PERSEC
#define DEFLECT_DIST 750
#define SHOTRANGE 3000
#define SHOTSPEED 40
#define DEFLECT_SPEED 25	/* ***BAV*** */
#define SHOOTABLE_FACTOR 3
#define DXDISPLACE 8000		/* ***BAV*** was 5000 */
#define DXOFFSET 7000		/* ***BAV*** was 10000 */
#define DYDISPLACE 2000
#define DISPLACE 5000		/* Used for offside and home planet entry */
#define OFFSET 10000
#define SITOUT_X 1000            /* Distance from edge for sitout */

/*
  If someone tries to play more than 256 rounds between each
  player, this will cause trouble.  Not likely. jn
*/

int scores[MAXTEAM+1];
int currp[MAXTEAM+1];
int lastp[MAXTEAM+1];

int faceoff = FACEOFF;		/* "faceoff" mode */
int period = 1;
int roboclock = 1;



extern int debug;
extern int oldmctl;
extern int hostile;
extern int sticky;
extern int practice;
extern int polymorphic;

extern int target;		/* robotII.c 7/27/91 TC */
extern int phrange;		/* robotII.c 7/31/91 TC */
extern int trrange;		/* robotII.c 8/2/91 TC */

extern int length;
extern struct planet *oldplanets;


marsmove()
{
    /***** Start The Code Here *****/


    HANDLE_SIG(SIGALRM,marsmove);

    me->p_ghostbuster = 0;         /* keep ghostbuster away */

#ifdef DOGDEBUG
    ERROR(2,("Enter marsmove\n"));
#endif

    /* Check that I'm alive */
    /* Messages are not checked when puck is not alive! */

    if (me->p_status != PALIVE){  /*So I'm not alive now...*/
      ERROR(2,("ERROR: Mars died??\n"));
      cleanup();    /*Mars is dead for some unpredicted reason like xsg */
    }

    roboclock++;
    player_maint();   			/* update necessary stats and info */
					/* Moved is up from after mars_rules */

    if (!(roboclock % (PERSEC*2))) do_msg_check();
    if (!(roboclock % (PERSEC*WARFUSE)))
      {
	do_war();
	checkstatus();
      }
    if (!(roboclock % (PERSEC*120))) mars_rules();


    
/* 
  first priority:  is this faceoff mode?

  For the dogfight server, faceoff mode is defined as the
  state where no contests are scheduled to occur, before
  anything has really started.
*/

    if (!inprogress)
      {
#ifdef DOGDEBUG
	ERROR(2,("Exit marsmove 1\n"));
#endif

	return;
      }

    if (faceoff > 0) {
	faceoff--;
	if (faceoff == 0) {
	    start_tourney();
	}
	else if ((faceoff % (10*PERSEC)) == 0) 
	{
	    messAll(255,roboname,"The tournament begins in %d seconds.", faceoff/PERSEC);
	}

        player_bounce();
#ifdef DOGDEBUG
	ERROR(2,("Exit marsmove 2\n"));
#endif
	return;           /* Do nothing else during faceoff mode */
    }



    /* keep all players in the rink */
    /* and do some other bouncing   */
    player_bounce();


    /* Some useful bookkeeping stuff here */
    if (!(roboclock % (PERSEC*120)))
      do_score();
    else if (!(roboclock % (PERSEC*10))) 
      recompute_all_kills();

    if (!(roboclock % (PERSEC*5))) udschedule();

#ifdef DOGDEBUG
      ERROR(2,("Exit marsmove 3\n"));
#endif

}  /* End of marsmove, the main dogfight overseeing program */


start_tourney()
{

  int i;
  struct player *j;
  Track *track;

  ERROR(4,("In start_tourney\n"));
  inprogress = 2;
  messAll(255,roboname,"War has broken out.");

  /* make sure these are done in a timely manner */
  do_war();		/* open hostilities */

  /* avoid dead slots, me, other robots (which aren't hostile) */
  for (i = 0, j = &players[i], track = &tracks[i];
       i < MAXPLAYER; i++, j++, track++) 
    {

      if ((j == me) || 
          (j->p_status == PFREE) ||
	  (track->t_flags & PU_FILLER) ||
	  (track->t_flags & PU_SITOUT))    /*ignore puck,filler,watchers*/ 
	continue;

      enter_contest(j,track);
    }

  udschedule();
}

checkstatus()
{

  int i;
  struct player *j;
  Track *track;
  int numplayers = 0;

  /* avoid dead slots, me, other robots (which aren't hostile) */
  for (i = 0, j = &players[i], track = &tracks[i];
       i < MAXPLAYER; i++, j++, track++) 
    {

      if ((j == me) ||
	  (j->p_status == PFREE) ||
	  (track->t_flags & PU_FILLER) ||
	  (track->t_flags & PU_SITOUT))    /*ignore puck,filler,watchers*/ 
	continue;

      numplayers++;
    }

  if (numplayers >= contestsize)
    {
      if (!inprogress)
	{
	  inprogress = 1;
	  faceoff = FACEOFF;
	}
    }
  else if (inprogress)
    {
      messAll(255,roboname,"Too many people have left.  The contest is over.");
      reset_game();
    }
}


enter_contest(j,track)
  struct player *j;
  Track *track;
{
  reset_player(j->p_no);

  track->t_flags |= PU_CONTEST;

  if (track->t_pos < 0) get_dog_stats(j,track);
}


udschedule()
{
  register int i,k,n;
  int avail[MAXPLAYER];
  struct player *j;
  Track *track;
  int schedule=0;

  if (inprogress != 2)
    return;

  k = 0;

  /* avoid dead slots, me, other robots (which aren't hostile) */
  for (i = 0, j = &players[i], track = &tracks[i];
       i < MAXPLAYER; i++, j++, track++)
    {

      if ((j == me) || 
	  (j->p_status != PALIVE) ||
	  (track->t_flags & PU_NOTAVAIL))    /*ignore puck,filler,watchers*/ 
	continue;

      avail[k++] = i;
    }

  avail[k]=0;
  if (k && (nextFreeArena()== -1)) 
    {
      messAll(255,roboname,"All arenas are full! Please wait for next available one.");
      return;
    }
  
/*
  This is just a quick gizmo to make sure the guy at the end
  of the line isn't always left waiting.
  Don't know if it's worth the CPU.
*/
#ifdef SCHEDULER
  if (k > 0)
    {
      int jumpsize;
      int tmp;
      int jumpto;

      jumpsize = random() % k;

      if (jumpsize)
	{
	  for (i=0;i<k;i++)
	    {
	      tmp = avail[i];

	      jumpto = (i + jumpsize) % k;

	      avail[i] = avail[jumpto];
	      avail[jumpto] = tmp;
	    }
	}
    }
#endif

  for (i=0;i<k;i++) 
    {
      if (avail[i]== -1) continue;
      for (n=i+1;n<k;n++) {
	if (avail[n]== -1) continue;
	schedule = get_num_matches(avail[i],avail[n]);
	if (schedule < nummatch) {
	  enterFight(avail[i],avail[n],nextFreeArena(),schedule);
	  avail[n]=avail[i]= -1;
	  break;
	}
      }

      if (nextFreeArena()== -1) break;
    }

    checkend();
}


checkend()
{
    register int i,k;
    struct player *p;

    /* First, we check that no one is dogfighting anymore */
    for(i=0,p=&players[0];i<MAXPLAYER;i++,p++) 
      {
	if (p->p_status == PFREE) continue;
	if (p == me) continue;
	if (tracks[i].t_flags & (PU_NOTCONTEST)) continue;
	if (tracks[i].t_flags & (PU_DOG|PU_WAIT)) 
	  {
#ifdef DOGDEBUG
	    ERROR(2,("Returning on %d",i));
#endif
	    return;
	  }
      }

    /* Next, we check that all schedules are played */
    for(i=0;i<MAXPLAYER;i++) 
      {
	if (tracks[i].t_flags & PU_NOTCONTEST) continue;
	if (players[i].p_status==PFREE) continue;
	if (i == me->p_no) continue;

	for (k=0;k<MAXPLAYER;k++) 
	  {
	    if (k == i) continue;
	    if (tracks[k].t_flags & PU_NOTCONTEST) continue;
	    if (k == me->p_no) continue;
	    if (players[k].p_status==PFREE) continue;

	    if (get_num_matches(i,k) < nummatch)
	      {
#ifdef DOGDEBUG
		ERROR(2,("Returning on %d %d",i,k));
#endif
		return;
	      }
	  }

	if (!toolate2join)
	  {
	    messAll(255,roboname,"No more players will be allowed to join the tournament until completed.");
	    toolate2join = 1;
	  }

	tracks[i].t_flags |= PU_DONE;
	tracks[i].t_flags &= ~PU_CONTEST;
      }

    player_maint();  /* seems to be necessary  -Jon */
    reset_game();
}

reset_game()
{
    /* Ok, now for the results */
  if (inprogress == 2) reportFinal();
    
  messAll(255,roboname,"Resetting game.");
  reset_all_players();
  inprogress = 0;
  toolate2join = 0;
  matchnum = 0;
}

/*  Display complete individual record for every player */
reportStats()
{
  int i;

  for(i=0;i<MAXPLAYER;i++) 
    {
      if (i == me->p_no) continue;
      if (players[i].p_status == PFREE) continue;
      if (tracks[i].t_flags & (PU_FILLER|PU_SITOUT)) continue;

      do_stats(i);
    }
}

reportFinal()
{
    messAll(255,roboname,"   *****   GAME IS COMPLETED!   *****");
    reportStats();
    reportStanding();
}

typedef struct playerlist {
    char name[16];
    char mapchars[2];
    float kills;
} Players;

reportStanding()
{
    register int i,k,l;
    register struct player *j;
    float kills;
    Players winners[MAXPLAYER+1];
    char buf[80],buf2[80];
    int number;


    recompute_all_kills();

    number=0;
    for (i = 0, j = &players[0]; i < MAXPLAYER; i++, j++) {
	if (j->p_status == PFREE) continue;
	if (j == me) continue;
	if (tracks[i].t_flags & PU_SITOUT) continue;

	kills= tracks[i].t_score;
	for (k = 0; k < number; k++) {
	    if (winners[k].kills < kills) {
		/* insert person at location k */
		break;
	    }
	}
	for (l = number; l >= k; l--) {
	    winners[l+1] = winners[l];
	}
	number++;
	winners[k].kills=kills;
	strncpy(winners[k].mapchars, j->p_mapchars, 2);
	strncpy(winners[k].name, j->p_name, 16);
	winners[k].name[15]=0;	/* `Just in case' paranoia */
    }

    messAll(255,roboname,"-----  RANKINGS:  -------");

    strcpy(buf,"");
    for (k=0; k < number; k+=2) {
	for (l=k;l<k+2;l++) {
	    if (l >= number) continue;
	    sprintf(buf2, "#%d:  %16s (%2.2s),%0.2f      ", l+1,
		winners[l].name, winners[l].mapchars,winners[l].kills);
	    strcat(buf,buf2);
	}
	messAll(255,roboname,buf);
	strcpy(buf,"");
    }
    return;
}


get_num_matches(a,b)
int a,b;
{
  int total;

  checkBadPlayerNo(a,"in get_num_matches a\n");
  checkBadPlayerNo(b,"in get_num_matches b\n");

  total = tracks[a].t_wins[b] + tracks[b].t_wins[a]
    + tracks[a].t_mutuals[b] + tracks[a].t_oggs[b];

  return(total);
}

/*  
 *  Additional routine start here
 */

cleanup()
{
    register struct player *j;
    register int i;

    /* Free the held slots - MK 9-20-92 */
    for (i=12, j = &players[i]; i < MAXPLAYER - TESTERS; i++, j++) {
        if ( j->p_status==POUTFIT && j->p_team==NOBODY){
            j->p_status = PFREE;
	}
    }

    if (!practice) {
	MCOPY(oldplanets, planets, sizeof(struct planet) * MAXPLANETS);
	for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) {
	    if ((j->p_status != PALIVE) || (j == me)) continue;
	    getship(&(j->p_ship), j->p_ship.s_type);
	}
    }
    exitRobot();
}

do_teleport_home(pno)
int pno;
{
  checkBadPlayerNo(pno, "in teleport_home\n");

  tracks[pno].t_flags &= ~(PU_DOG|PU_WAIT);

  go_arena(0,pno,0);
}


do_teleport_arena(ano,j,position)
int ano;
struct player* j;
int position;
{
    Arena *a;
    Track *track;

    /*Cleaned up this routine for v2 - MK*/

    if (!j)
      {
	ERROR(2,("NULL passed to teleport_arena\n"));
	return;
      }

    if (j == me)
      {
	ERROR(2,("Tried to teleport self.\n"));
	return;
      }

    checkBadArenaNo(ano,"new in teleport\n");
    a = &arenas[ano];
    track = &tracks[j->p_no];


    if (j->p_status == PALIVE)
      {

	if (ano == 0)
	  {
	    j->p_y = planets[STARTPLANET].pl_y
	      + (random() % (2*DISPLACE) - DISPLACE);

	    j->p_x = planets[STARTPLANET].pl_x 
	      + (random() % (2*DISPLACE) - DISPLACE);
	  }
	else
	  {
#ifdef DOG_RANDOM
	    j->p_x = a->a_x + (2 * position - 1) * (10000 + (random() % 4500));
	    j->p_y = a->a_y - (2 * position - 1) * (random() % 9000);
#else
	    j->p_x = a->a_x + (2 * position - 1) * 9000;
	    j->p_y = a->a_y - (2 * position - 1) * 6000;
#endif
	  }
	
	smileon(j);

	track->t_x = j->p_x;
	track->t_y = j->p_y;
      }

    track->t_arena = ano;

    a->a_free = 0;
}


int nextFreeArena()
{
    register int i;
    Arena* a;

    for(i=1, a = &arenas[1];i<MAXARENAS;i++, a++) {
	if (a->a_free) return i;
    }

    return (-1);
}



/* fully heal this dude */
smileon(j)
struct player* j;
{
  register struct torp *t;
  j->p_speed = 0;
  j->p_desspeed = 0;
  j->p_subspeed = 0;
  j->p_flags = PFSHIELD;
  j->p_fuel   = j->p_ship.s_maxfuel;
  j->p_shield = j->p_ship.s_maxshield;
  j->p_damage = 0;
  j->p_wtemp = 0;
  j->p_etemp = 0;
  j->p_ntorp = 0;
  for (t = firstTorpOf(j); t <= lastTorpOf(j); t++)
    t->t_status = TFREE;
  j->p_cloakphase = 0;
}


do_msg_check()
{
    while (oldmctl!=mctl->mc_current) {
	oldmctl++;
	if (oldmctl >= MAXMESSAGE || oldmctl < 0) oldmctl=0;
	if (messages[oldmctl].m_flags & MINDIV) {
	    if (messages[oldmctl].m_recpt == me->p_no)
		check_command(&messages[oldmctl]);

	} else if (messages[oldmctl].m_flags & MALL) {
	    if (strstr(messages[oldmctl].m_data, "help") != NULL)
		messOne(255,roboname,messages[oldmctl].m_from,
                   "If you want help from me, send me the message 'help'.");
	}
    }
}



/* Added by MK */
/* ARGSUSED */
do_version(comm,mess)
char *comm;
struct message *mess;
{
    int who;

    who = mess->m_from;

    messOne(255,roboname,who, "Mars Version 1.0 - Beta Release Version");
    messOne(255,roboname,who, "Please mail bug/comments to nelson@math.arizona.edu");
}


/* ARGSUSED */
do_stats_msg(comm,mess)
char *comm;
struct message *mess;
{
    int who;

    who = mess->m_from;

    do_stats(who);
}

do_stats(who)
int who;
{
    register int i;
    register Track *track;
    register struct player *j;

    checkBadPlayerNo(who,"in do_stat\n");

    messOne(255,roboname,who,"You must play %d games with each person.",nummatch);
    messOne(255,roboname,who,"You must have %d people to start the game.",contestsize);

    if (inprogress < 2)
      {
        messOne(255,roboname,who,"The tournament has not started yet.");
	return;
      }
    
    messOne(255,roboname,who,"Your record so far:");

    track = &tracks[who];

    for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) 
      {
	if (j == me) continue;
	if (tracks[i].t_flags & (PU_FILLER|PU_SITOUT)) continue;
	if (j->p_status == PFREE) continue;
	if (i==who) continue;

	messOne(255,roboname,who, " %2s: %-16s  %2dW %2dL %2dM %2dO  %3d left  %3d min",
	      j->p_mapchars,
	      j->p_name,
	      track->t_wins[i],
	      tracks[i].t_wins[who],
	      track->t_mutuals[i],
	      track->t_oggs[i],
	      nummatch - get_num_matches(i,who),
	      tracks[i].t_seconds / 60);
      
      }
}

/*
  Remove some jerk from the score keeping
*/
dont_score(pno)
int pno;
{
  int i;
  Track *track;

  if (!inprogress)
    return;

  checkBadPlayerNo(pno,"in don't score\n");

  for (i = 0, track = &tracks[i];
       i < MAXPLAYER; i++, track++) 
    {
      /*Skip free slots, space filler, and puck */

      track->t_mutuals[pno] = 0;
      track->t_oggs[pno] = 0;
      track->t_wins[pno] = 0;
    }

  recompute_all_kills();
}

/* ARGSUSED */
do_force_newgame(mflags,sendto)
int mflags,sendto;
{

/****MK - stats are cleared*/
#ifdef NEWGAME_RESET

    messAll(255,roboname,"Clearing Player Stats for the Newgame");
    reset_game();

#else
    messAll(255,roboname,"NEWGAME is disabled on this server.");

#endif
/****End added code */

}

do_war()
{
    register int i;
    register struct player *j;

    if (practice) return;
    for (i = 0; i < 40; i++) {	/* ***BAV*** */
	planets[i].pl_armies = 2;
    }
    for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) {

#ifdef DOGFILLER
	if (i>11 && i<MAXPLAYER-TESTERS && j->p_status==PFREE) { /* **BAV** */
	    j->p_status = POUTFIT;  /* Mark a few players slots as busy */
	    j->p_team = NOBODY;
	    j->p_ghostbuster = -2147483000;
            tracks[i].t_flags = PU_FILLER;
	}
#endif

	if ((j->p_status == PALIVE) && (j != me)) 
	  {
	    tracks[i].t_seconds += WARFUSE;

	    declare_selfhate(j);
	  
	    j->p_armies = 0;
	  }
    }
}

/* ARGSUSED */
do_join(comm,mess)
char *comm;
struct message *mess;
{
    int who;

    who = mess->m_from;
    join(who);
}

join(who)
int who;
{ 
  Track *track;

  track = &tracks[who];

/*
  if (!(track->t_flags & PU_FILLER))
	track->t_flags |= PU_FILLER;
*/
  
  /*If you have already joined, do nothing*/
  if (track->t_flags & (PU_CONTEST|PU_DONE))
    {
      messOne(255,roboname,who,"You have already joined.");
      return;
    }

  if (!inprogress || !toolate2join)
    {
      messAll(255,roboname,"Oh, look who's decided to grace us with his presence: %s (%c)", 
	    players[who].p_name, shipnos[who]);

      join_game(track);
    }
  else
    {
      messOne(255,roboname,who,"It is too late to join this game.");
      track->t_flags |= PU_SITOUT;
    }
}

join_game(track)
Track *track;
{
  
  /*If you are already sitting out, do nothing*/
  track->t_flags = 0;

  reset_player(track->t_no);
  if (inprogress == 2) 
    track->t_flags |= PU_CONTEST;

  if (track->t_pos < 0) get_dog_stats(&players[track->t_no],track);
  /* reset preferred ship; not initialized elsewhere, funny things happened */
  track->t_preferred = BATTLESHIP;
}


/* ARGSUSED */
do_sitout(comm,mess)
char *comm;
struct message *mess;
{
    int who;
    struct player *j;
    Track *track;

    who = mess->m_from;
    j = &players[who];
    track = &tracks[who];

    /*If you are already sitting out, do nothing*/
    if (track->t_flags & PU_NOTCONTEST)
      {
	messOne(255,roboname,who,"You are already sitting out");
	return;
      }

    if (inprogress == 2)
      {
#ifdef ALLOWQUIT
	reset_player(who);
	dont_score(who);
#else
	messOne(255,roboname,who,"What, you chicken! Go fight!");
	return;
#endif
      }

    messAll(255,roboname,"%s (%c) has decided to watch, what a twink.", 
	    players[who].p_name, shipnos[who]);

    do_teleport_home(who);

    track->t_flags |= PU_SITOUT ;

    j->p_speed = 0;                      /*So you don't move        */
    j->p_desspeed = 0;
    j->p_subspeed = 0;
    j->p_flags = PFSHIELD;               
    j->p_fuel   = 0;                     /*Hah, you're hosed anyway */
    j->p_damage = j->p_ship.s_maxdamage - 5;
    j->p_shield = j->p_ship.s_maxshield; /*OK, a potential help     */

}


mars_rules()
{
    messAll(255,roboname,"Welcome to the Dogfight Challenge.");
    messAll(255,roboname,"Send me the message \"help\" for rules.");
}

do_preferred_ship(comm,mess)
char *comm;
struct message *mess;
{
    int who;
    char shiptype[2];
    int shipnum;

    who = mess->m_from;

    checkBadPlayerNo(who,"in do_prefered_ship");

    sscanf(comm,"SHIP %2s",shiptype);

    shipnum = lookupshipname(shiptype);

    /*
      The default is no starbases or ATTs
   */
    if (shipnum >= 0 && shipnum < ALLOWED_SHIPS) {
	tracks[who].t_preferred = shipnum;
	messOne(255,roboname,who,"Preferred ship type set to: %s",shipnames[shipnum]);
    }
    else {
	messOne(255,roboname,who,"I don't recognize that type of ship.");
	messOne(255,roboname,who,"How about BB, CA, DD, or SC?");
    }
}

lookupshipname(shipname)
char *shipname;
{
    int i;

    for (i = 0; i < NUM_TYPES; i++) {
	if (strncasecmp(shipname,shiptypes[i],2) == 0)
	return(i);
	if (strcasecmp(shipname,shipnames[i]) == 0)
	return(i);
    }

    return (-1);
}

do_score()
{
  if (inprogress==2)
    reportStanding();
}

/* ARGSUSED */
do_score_msg(comm,mess)
char *comm;
struct message *mess;
{
    int who;

    who = mess->m_from;

    if (inprogress==2)
	reportStanding();
    else
	messOne(255,roboname,who,"The tournament has not yet started.");
}

/* ARGSUSED */
do_status_msg(comm,mess)
char *comm;
struct message *mess;
{
    int who;

    who = mess->m_from;

    checkBadPlayerNo(who,"in do_status_msg");

    if (!inprogress)
	messOne(255,roboname,who,"The tournament has not yet started.");
    else if (inprogress == 1)
	messOne(255,roboname,who,"Faceoff is occuring now.");
    else
	messOne(255,roboname,who,"The tournament is in progress.");

    if (tracks[who].t_flags & PU_SITOUT)
	messOne(255,roboname,who,"You are sitting out.");
    if (tracks[who].t_flags & PU_CONTEST)
	messOne(255,roboname,who,"You are a contestant.");
    if (tracks[who].t_flags & PU_DONE) {
	messOne(255,roboname,who,"You are done with all dogfights, but you must");
	messOne(255,roboname,who,"remain so scores can be totalled.");
    }
    if (tracks[who].t_flags & PU_DOG)
	messOne(255,roboname,who,"You are currently in a tournament dogfight.");
    if (tracks[who].t_flags & PU_WAIT)
	messOne(255,roboname,who,"You are waiting to receive credit for a kill.");
}


	
player_maint()
{
  int i;
  struct player *j;
  struct player *enemy;
  Track *etrack;
  Track *track;
  int eno;
  
  /* avoid dead slots, me, other robots (which aren't hostile) */
  for (i = 0, j = &players[i], track = &tracks[i];
       i < MAXPLAYER; i++, j++, track++) 
    {
      if (j->p_pos > 0) j->p_pos = -1;		/* Don't save player stats */
 
      if ((j == me) || (track->t_flags == PU_FILLER)) /*ignore puck,filler*/ 
	continue;

      if (j->p_status != PALIVE) {       /*for dead people*/

	j->p_team = ROM;

	if ((j->p_status == PFREE) &&
	    (track->t_status != j->p_status)) 
	  {
	    free_player(i);
	    if (inprogress && (track->t_flags & (PU_CONTEST|PU_DONE)))
	      {
		messAll(255,roboname,"%s (%c) has left the game!!!  Removing his effect on the scores.", 
			j->p_name, shipnos[i]);
		dont_score(i);
	      }
	  }
	else if (track->t_flags & (PU_DOG))
	  {
	    track->t_flags &= ~PU_DOG;

	    /* The player died in a tournament dogfight */
	    
	    if (track->t_flags & PU_WAIT)
	      {
		/*
		  Somehow the enemy killed this player after he died.
		  Consider how to divide credit.
	        */
		
		track->t_flags &= ~PU_WAIT;

		eno = track->t_opponent;
		checkBadPlayerNo(eno,"in maint\n");
		enemy = &players[eno];
		etrack = &tracks[eno];

		if (j->p_whydead == KSHIP)
		  {
		    if (enemy->p_whydead == KSHIP)
		      {
			/* this should not happen, but just in case */
			ogg_credit(track,j,eno);
			ogg_credit(etrack,enemy,i);
		      }
		    else
		      {
			mutual_credit(track,j,eno);
			ogg_credit(etrack,enemy,i);
		      }
		  }
		else
		  {
		    mutual_credit(track,j,eno);
		    mutual_credit(etrack,enemy,i);
		  }

	      }
	    else
	      {
		/*
		  This player was killed first by his enemy.
		  Place enemy in wait mode, credit is decided
		  when fate of enemy is known.
		*/
		
		eno = track->t_opponent;
		checkBadPlayerNo(eno,"in maint\n");
		enemy = &players[eno];
		etrack = &tracks[eno];

		if (!(etrack->t_flags & PU_DOG))
		  {
		    /* 
		      something weird is going on.. enemy not dogfighting, 
		      remove both player and enemy from dogfight mode
		    */
		    messAll(255,roboname,"Something weird is going on with %s (O%c)!!", 
			    j->p_name, shipnos[i]);
		    reset_dogfight(i);
		    continue;
		  }

		etrack->t_flags |= PU_WAIT;
		etrack->t_wait = 6*PERSEC;
	      }	    
	  }

	track->t_opponent = -1;
	track->t_status = j->p_status;
	do_teleport_home(i);

	continue;		/* do nothing else for dead players */
      }
      
      
      /*At this point, the player is alive*/	
      
      if (track->t_flags & PU_DOG)
	{
	  /* increment time in the arena */
	  j->p_stats.st_tticks = ++(track->t_stats.d_ticks); 

	  if (track->t_flags & PU_WAIT)
	    {
	      track->t_wait--;

	      if (track->t_wait == 0)
		{
		  /*
		    This player survived long enough past the enemy's death!  
		    He gets full credit!!
		  */
		  track->t_flags &= ~PU_WAIT;

		  eno = track->t_opponent;
		  checkBadPlayerNo(eno,"in maint\n");
		  enemy = &players[eno];
		  etrack = &tracks[eno];

		  win_credit(track,j,eno);
		  loss_credit(etrack,enemy,i);

		  track->t_opponent = -1;
		  track->t_flags &= ~PU_DOG;
		  do_teleport_home(i);
		}
	    }
	  else
	    {
	      eno = track->t_opponent;
	      checkBadPlayerNo(eno,"in maint\n");
	      enemy = &players[eno];
	      etrack = &tracks[eno];

	      if (!(etrack->t_flags & PU_DOG))
		{
		  /*
		    Somethings up... my enemy isn't in dogfight mode...
		  */
		  messAll(255,roboname,"%s (%c) can't find his enemy: %s (%c)", 
			    j->p_name, shipnos[i],
			    enemy->p_name, shipnos[eno]);
		  reset_dogfight(i);
		  continue;
		}
	    }
	}
      else if ((inprogress == 2) &&
	       !(track->t_flags & (PU_SITOUT|PU_DONE|PU_CONTEST)))
	{
	  printf("FLAGS: 0x%x\n",track->t_flags);
	  /* A new victim has arrived. */
	  join(i);
	}

      /* Save current info */
      track->t_status = j->p_status;
      track->t_x = j->p_x;
      track->t_y = j->p_y;
      
      /* Note: track->t_seconds is updated in do_war */
      
    }
}


/*
  go_arena
*/
enterFight(a, b, ano, schedule)
int a, b, ano, schedule;
{
    /* 1. Removes arena_num from free arena list    D>
       2. Sets p_pflag & PFDOG			    <D>
       3. Announces fight				*/

    char buf[80];
    struct player *p1, *p2;
    int times_fought = 0, shiptype1 = 0, shiptype2 = 0;
    Track *tr1;
    Track *tr2;

    checkBadPlayerNo(a,"in enterFight a\n");
    checkBadPlayerNo(b,"in enterFight b\n");
    checkBadArenaNo(ano,"in enterFight\n");

    p1 = &players[a];
    p2 = &players[b];
    tr1 = &tracks[a];
    tr2 = &tracks[b];

    if (p1 == me || p2 == me) {
	ERROR(2,("Just tried to enter myself in a fight.  Exitting.\n"));
	cleanup();
    }
	
    /* announces match */
    sprintf(buf,"[MATCH %d] %s(%c%c) versus %s(%c%c) in arena %d!",
	    matchnum++,p1->p_name,
	    teamlet[p1->p_team],shipnos[p1->p_no],p2->p_name,
	    teamlet[p2->p_team],shipnos[p2->p_no],ano);
    messAll(255,roboname,buf);
    messOne(255,roboname,a,buf);
    messOne(255,roboname,b,buf);
    
    times_fought = (schedule % 5);
    switch(times_fought) {
	case 0:
	    shiptype1 = shiptype2 = BATTLESHIP;
	    break;
	case 1:
	    shiptype1 = shiptype2 = CRUISER;
	    break;
	case 2:
	    shiptype1 = shiptype2 = DESTROYER;
	    break;
	case 3:
	    shiptype1 = shiptype2 = SCOUT;
	    break;
	case 4:
	    shiptype1 = tr1->t_preferred;
	    shiptype2 = tr2->t_preferred;
	    break;
	default:
	    shiptype1 = shiptype2 = -1;	/* don't change their ship type */
	    break;
    }
    if (shiptype1 != -1)
	getship(&p1->p_ship, shiptype1);
    if (shiptype2 != -1)
	getship(&p2->p_ship, shiptype2);

    tr1->t_opponent = b;
    tr2->t_opponent = a;
    tr1->t_flags |= PU_DOG;
    tr2->t_flags |= PU_DOG;

    go_arena(ano,a,0);
    go_arena(ano,b,1);
}


/* Rule 1)  Love your enemies, hate your friends */
declare_selfhate(j)
struct player *j;
{
#ifdef NO_BRUTALITY
  if (j->p_team == ROM)
    j->p_hostile &= ~(ALLTEAM);
  else
#endif
    {
      j->p_hostile &= ~(ALLTEAM & ~j->p_team);
      j->p_hostile |= j->p_team;
    }
  j->p_war = (j->p_swar | j->p_hostile);
}

/*
  Remove a playera from whatever arena currently in, 
  place them in the new arena.
  Also heals, switches the player's team, and declares war.
*/
go_arena(ano,pno,position)
int ano;
int pno;
int position;
{
  Arena *old_a = NULL;
  Track *track;
  struct player *j;

  checkBadPlayerNo(pno,"in go_arena");

  j = &players[pno];
  smileon(j);

  track = &tracks[j->p_no];
     
  if (badArenaNo(track->t_arena))
    {
      ERROR(2,("Bad old arena number %d for %d.  Resetting player\n",
	       old_a ? (int)(old_a->a_no) : -1, pno));
      reset_player(pno);
      return;
    }

  old_a = &arenas[track->t_arena];


  checkBadArenaNo(ano,"in teleport\n");



  if (ano == 0)
    {
      j->p_team = ROM;
    }
  else
    {
      switch (ano % 3)
	{
	case 0:
	  j->p_team = FED;
	  break;
	case 1:
	  j->p_team = KLI;
	  break;
	default:
	  j->p_team = ORI;
	  break;
	}
    }

  /* Rule 1)  Love your enemies, hate your friends */
  declare_selfhate(j);
  
  do_teleport_arena(ano, j, position);
 
  check_arena_free(old_a->a_no);
}


check_arena_free(ano)
int ano;
{
  int i;
  Track *track;
  struct player *j2;

  
  checkBadArenaNo(ano,"check_arena\n");

  if (ano == 0) return 1;


  for (i = 0, j2 = &players[i], track = &tracks[i];
       i < MAXPLAYER; i++, j2++, track++) 
    {
      if ((j2 == me) || 
	  (j2->p_status!=PALIVE))
	continue;  /*Don't do this for dead and for puck*/

      if (track->t_arena == ano)
	{
	  arenas[ano].a_free = 0;
	  return 0;
	}
    }

  arenas[ano].a_free = 1;
  return 1;
}


recompute_kills(j2)
struct player* j2;
{
  int i;
  Track *track;
  Track *track2;
  struct player *j;
  float kills;


  track2 = &tracks[j2->p_no];
  kills = 0.0;

  for (i = 0, j = &players[i], track = &tracks[i];
       i < MAXPLAYER; i++, j++, track++) {

	if (j == me) continue;
	if (track->t_flags & (PU_FILLER|PU_SITOUT)) continue;
	if (j->p_status == PFREE) continue;
	if (j==j2) continue;

      kills += (float)( (float)(track2->t_wins[i])
	    + (float)OGGVALUE * (float)(track2->t_oggs[i])
	    + (float)MUTUALVALUE * (float)(track2->t_mutuals[i]));
    }

  j2->p_kills = track2->t_score = kills;

  /* this updates the shared memory so the player can see stats */
  j2->p_stats.st_tkills = track2->t_stats.d_mutuals +
                          track2->t_stats.d_wins + track2->t_stats.d_oggs;
  j2->p_stats.st_tarmsbomb = track2->t_stats.d_wins + track2->t_stats.d_oggs;
  j2->p_stats.st_tplanets = track2->t_stats.d_wins;
  j2->p_stats.st_tlosses = track2->t_stats.d_losses;
}


/*
  recompute all kills, just to be sure the server didn't
  pull a fast one on us
*/

recompute_all_kills()
{
    register int i;
    register struct player *j;

    for (i = 0, j = &players[i];
	 i < MAXPLAYER; i++, j++) 
      {

	if ((j == me) ||
	    (j->p_status == PFREE))
	  continue;
	
	recompute_kills(j);
      }
}

reset_all_players()
{
    register int i;
    register struct player *j;

    for (i = 0, j = &players[i];
	 i < MAXPLAYER; i++, j++) {
      if ((j->p_status != PFREE) && !(j->p_flags & PFROBOT)) {
	reset_player(j->p_no);
      }
    }
}

zero_stats(track)
Track *track;
{
    MZERO(track->t_mutuals, sizeof(track->t_mutuals[0]) * MAXPLAYER);
    MZERO(track->t_oggs, sizeof(track->t_oggs[0]) * MAXPLAYER);
    MZERO(track->t_wins, sizeof(track->t_wins[0]) * MAXPLAYER);
/*
    MZERO(track->t_votes, sizeof(track->t_votes[0]) * PV_TOTAL);
*/
}


/* 
  fully reset this guy

  This throws the player out of the contest
  It is generally appropriate to use dont_score() with this
*/
reset_player(pno)
int pno;
{
  Track *track;

  checkBadPlayerNo(pno,"in reset_player\n");

#ifdef DOGDEBUG
  ERROR(2,("Resetting %d\n",pno));
#endif


  track = &tracks[pno];

  zero_stats(track);

  track->t_opponent   = -1;
  track->t_wait   = 0;

  if ((inprogress == 2) && (track->t_flags & PU_CONTEST))
    track->t_flags   = PU_CONTEST;
  else if (track->t_flags & PU_SITOUT)
    track->t_flags   = PU_SITOUT;
  else
    track->t_flags   = 0;

  do_teleport_home(pno);

  track->t_score = 0.0;
  track->t_seconds = 0;
}

/* free player so someone else can use this slot */
free_player(pno)
int pno;
{
  Track *track;

  checkBadPlayerNo(pno,"in reset_player\n");

  ERROR(3,("Freeing player %d\n",pno));

  track = &tracks[pno];

  zero_stats(track);

  track->t_score = 0.0;
/*		- nbt
  track->t_flags = 0;
*/
/*
  track->t_flags = PU_FILLER;
*/
  track->t_flags = PU_SITOUT;

  track->t_seconds = 0;
  track->t_opponent   = -1;
  track->t_wait   = 0;

  /* resets tournament stats of player */
  track->t_pos = -1;
  MZERO(&(track->t_stats), sizeof(DogStat));
  track->t_stats.d_ticks = 1;
}


/* 
  reset this guy and his current dogfight

  This keeps the player in the game, but immediately resets
  the current dogfight he was in.  Scoring should not be
  hurt in anyway (knock on wood).
*/
reset_dogfight(pno)
int pno;
{
  Track *track;
  Track *etrack;
  int eno;


  checkBadPlayerNo(pno,"in reset_dogfight\n");

  track = &tracks[pno];

  eno = track->t_opponent;
  track->t_opponent   = -1;
  track->t_wait   = 0;

  if (inprogress == 2)
    track->t_flags   = PU_CONTEST;
  else
    track->t_flags   = 0;

  do_teleport_home(pno);


  if (inprogress && !badPlayerNo(eno))
    {
      etrack = &tracks[eno];
  
      /* make sure opponent hasn't joined another fight already */
      if (etrack->t_opponent == pno)
	{
	  etrack->t_opponent = -1;
	  etrack->t_wait   = 0;

	  if (etrack->t_flags & PU_CONTEST)
	    etrack->t_flags   = PU_CONTEST;
	  else
	    etrack->t_flags   = 0;

	  do_teleport_home(eno);
	}
    }
}

player_bounce()
{
    register int i;
    register struct player *j;
    register Track *track;
    register struct torp *t;
    Arena* a;

    /* avoid dead slots, me, other robots (which aren't hostile) */
    for (i = 0, j = &players[i], track = &tracks[i];
           i < MAXPLAYER; i++, j++, track++) {
        if ( (j == me) || (j->p_status!=PALIVE) )
            continue;  /*Don't do this for dead and for puck*/


	a = &arenas[track->t_arena];

	/* kill torps that might distract guys in other arenas */

	for (t = firstTorpOf(j); t <= lastTorpOf(j); t++) 
	  if (t->t_x < a->a_left ||
	      t->t_x > a->a_right ||
	      t->t_y < a->a_top ||
	      t->t_y > a->a_bottom)
	  {
	    fprintf(stderr, "here!\n");
	    t->t_status = TFREE;
	    switch (t->t_type) {
	      case TPHOTON: j->p_ntorp--; break;
	      case TPLASMA: j->p_nplasmatorp--; break;
	    }
	  }

#ifdef WALL_BOUNCE
        /* Hit/bounce off the boards */
        if (j->p_x < a->a_left) 
	  {      
	    j->p_flags &= ~PFORBIT;
	    if (j->p_dir == 192)
	      j->p_dir = j->p_desdir = 64;
	    else
	      j->p_dir = j->p_desdir = 64 - (j->p_dir - 192);

	    j->p_x = a->a_left;
	  } 
	else if (j->p_x > a->a_right) 
	  {
	    j->p_flags &= ~PFORBIT;
	    if (j->p_dir == 64)
	      j->p_dir = j->p_desdir = 192;
	    else
	      j->p_dir = j->p_desdir = 192 - (j->p_dir - 64);

	    j->p_x = a->a_right;
	  }
        if (j->p_y < a->a_top) 
	  {
	    j->p_flags &= ~PFORBIT;
	    if (j->p_dir == 0)
	      j->p_dir = j->p_desdir = 128;
	    else
	      j->p_dir = j->p_desdir = 128 - j->p_dir;

	    j->p_y = a->a_top;
	  } 
	else if (j->p_y > a->a_bottom) 
	  {
	    j->p_flags &= ~PFORBIT;
	    if (j->p_dir == 128)
	      j->p_dir = j->p_desdir = 0;
	    else
	      j->p_dir = j->p_desdir = 128 - j->p_dir;

	    j->p_y = a->a_bottom;
	  }
#else
        /* Bounce - and stick */
        if (j->p_x < a->a_left) 
	  {
	    j->p_flags &= ~PFORBIT;
	    j->p_x = a->a_left;
	  } 
	else if (j->p_x > a->a_right) 
	  {
	    j->p_flags &= ~PFORBIT;
	    j->p_x = a->a_right;
	  }
        if (j->p_y < a->a_top) 
	  {
	    j->p_flags &= ~PFORBIT;
	    j->p_y = a->a_top;
	  } 
	else if (j->p_y > a->a_bottom) 
	  {
	    j->p_flags &= ~PFORBIT;
	    j->p_y = a->a_bottom;
	  }
#endif

    } /*end for loop*/

}


exitRobot()
{
    SIGNAL(SIGALRM, SIG_IGN);
    if (me != NULL && me->p_team != ALLTEAM) {
	if (target >= 0) {
	    messAll(255,roboname, "I'll be back.");
	}
	else {
	    messAll(255,roboname,"#############################");
	    messAll(255,roboname,"#");
            messAll(255,roboname,"#  Venus awaits...");
	    messAll(255,roboname,"#");
	}
    }
    
    freeslot(me);
    
    exit(0);
}


init_mars()
{
  int i;
  Arena *a;
  Track *track;
  struct player *j;

#ifdef DOGDEBUG
  ERROR(1,("init_mars\n"));
#endif
  
  /* 
    want to make sure this happens REAL FAST, want to make sure no one
    suffers from stat hosing.
  */

  for (i = 0, j = &players[i];  i < MAXPLAYER; i++, j++) 
    if (j->p_pos > 0) j->p_pos = -1;		/* Don't save player stats */

  for (i = 1, a = &arenas[1]; i < 9; i++, a++)
    {
      a->a_no = i;
      a->a_free = 1;
      a->a_top = 10000 + ((i-1) % 4 * 20000);
      a->a_bottom = 20000 + a->a_top;

      if (i-1 < 4) 
	a->a_x = 20000;
      else 
	a->a_x = 80000;

      a->a_y = 20000 + ((i-1) % 4 * 20000);

      if (i-1 < 4) 
	{
	  a->a_left = LEFT1;
	  a->a_right = RIGHT1;
	}
      else 
	{
	  a->a_left = LEFT2;
	  a->a_right = RIGHT2;
	}
    }

  a = &arenas[0];

  a->a_no = 0;
  a->a_free = 1;        /* this should never be checked, home always free */
  a->a_top = VERT2;
  a->a_bottom = VERT4;
  a->a_left = RIGHT1;
  a->a_right = LEFT2;

  for (i = 0, track = &tracks[i];
       i < MAXPLAYER; i++, track++) 
    {
      free_player(i);
      track->t_arena = 0;
      track->t_no = i;
    }
  reset_all_players();      
}

ogg_credit(track,j,i)
Track *track;
struct player *j;
int i;
{
  track->t_oggs[i]++;
  track->t_stats.d_oggs++;
  track->t_stats.d_losses++;

  recompute_kills(j);
  savedogplayer(j, track);
}

win_credit(track,j,i)
Track *track;
struct player *j;
int i;
{
  track->t_wins[i]++;
  track->t_stats.d_wins++;

  recompute_kills(j);
  savedogplayer(j, track);
}

mutual_credit(track,j,i)
Track *track;
struct player *j;
int i;
{
  track->t_mutuals[i]++;
  track->t_stats.d_mutuals++;
  track->t_stats.d_losses++;

  recompute_kills(j);
  savedogplayer(j, track);
}

loss_credit(track,j,i)
Track *track;
struct player *j;
int i;
{
  track->t_stats.d_losses++;

  recompute_kills(j);
  savedogplayer(j, track);
}


savedogplayer(victim, tr)
struct player *victim;
Track *tr;
{
    int fd;

    if (tr->t_pos < 0) return;
    if (victim->p_stats.st_lastlogin == 0) return;
    if (victim->p_flags & PFROBOT) return;

    fd = open(DogStats, O_WRONLY, 0644);
    if (fd >= 0) {
	lseek(fd, 16 + tr->t_pos * sizeof(DogStat) ,0);
	write(fd, (char *) &tr->t_stats, sizeof(DogStat));
	close(fd);
    }
}


get_dog_stats(j,track)
struct player *j;
Track *track;
{
   static DogStatEntry player;
   static int position= -1;
   int plfd;
   int i;
   int entries;
   struct stat buf;

/*
   printf("dogstat: %d dogstatentry: %d\n",
	  sizeof(DogStat),sizeof(DogStatEntry));
*/

   MZERO(&(track->t_stats), sizeof(DogStat));
   MZERO(&player, sizeof(DogStatEntry));

   track->t_stats.d_ticks = 1;
   player.dstats.d_ticks = 1;
  
   for (;;) {     /* so I can use break; */
     plfd = open(DogStats, O_RDONLY, 0644);
     if (plfd < 0) {
       /* this might be a result of the file not existing, created below */
       ERROR(1,("I cannot open the mars player file! (will try to create)\n"));
       strncpy(player.name, j->p_name, 16);
       position= -1;
       ERROR(1,("Error number: %d\n", errno));
       break;
     }
     position=0;
     while (read(plfd, (char *) &player, sizeof(DogStatEntry)) ==
	    sizeof(DogStatEntry)) {
       if (strcmp(j->p_name, player.name)==0) {
	 close(plfd);
	 break;
       }
       position++;
     }
     if (strcmp(j->p_name, player.name)==0) break;
     close(plfd);
     position= -1;
     strncpy(player.name, j->p_name,16);
     break;
   }
   
   if (position == -1) 
     {
       strncpy(player.name, j->p_name, 16);
       MZERO(&player.dstats, sizeof(DogStat));
       player.dstats.d_ticks = 1;
       
       plfd = open(DogStats, O_RDWR|O_CREAT, 0644);
       if (plfd < 0) 
	 {
	   ERROR(1,("Failure to access dogfight file."));
	 }
       else
	 {
	   fstat(plfd, &buf);
	   stat(DogStats,&buf);
	   entries = buf.st_size / sizeof(DogStatEntry);
	   lseek(plfd, entries * sizeof(DogStatEntry), 0); 
	   
	   write(plfd, (char *) &player, sizeof(DogStatEntry));
	   close(plfd);
	   track->t_pos = entries;
	   MCOPY(&player.dstats, &(track->t_stats), sizeof(DogStat));
	 }
     }
   
   recompute_kills(j);
}




