/*
 * inl.c
 *
 * INL server robot by Kurt Siegl
 * Based on basep.c
 *
 * Many improvements by Kevin O'Connor
 *
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <signal.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <errno.h>
#include <pwd.h>
#include <ctype.h>
#include <time.h>
#include "defs.h"
#include "struct.h"
#include "data.h"
#include "planets.h"
#include "inldefs.h"
#include INC_STRINGS

int debug=0;

struct planet *oldplanets;      /* for restoring galaxy */
struct planet *inl_planets;
struct itimerval udt;

int 	oldmctl;
FILE	*inl_log;

char time_msg[4][10] = {"seconds", "second", "minutes", "minute"};

Team	inl_teams[INLTEAM+1] = { 
		{ HOME, "home", "Home", NONE, HOMETEAM, NOT_CHOOSEN, 17, 
		  90, 30, 0, 1 ,10},
		{ AWAY, "away", "Away", NONE, AWAYTEAM, NOT_CHOOSEN, 17, 
		  90, 30, 0, 1, 10}
		};
Sides	sides[MAXTEAM+1] = { {"FED", FED, 2},
			     {"ROM", ROM, 3},
			     {"KLI", KLI, 0},
			     {"ORI", ORI, 1}};

int cbounds[9][4] =
{
  {0, 0, 0, 0},
  {0, 45000, 55000, 100000},
  {0, 0, 55000, 55000},
  {0, 0, 0, 0},
  {45000, 0, 100000, 55000},
  {0, 0, 0, 0},
  {0, 0, 0, 0},
  {0, 0, 0, 0},
  {45000, 45000, 100000, 100000}
};

char    *roboname = "INL";
char	*inl_from = {"INL->ALL"};

Inl_stats inl_stat = { 17, 1, S_PREGAME, 0 , 0, 0, 0, 0};
Inl_countdown inl_countdown = 
	{0,{60,30,10,5,4,3,2,1,0,-1},8,0,PERSEC,NULL,""};

int end_tourney();
Inl_countdown inl_game = 
	{0,{2700,600,300,120,60,30,10,5,4,3,2,1,0,-1},12,0,PERSEC,end_tourney,""};

/* XXX Gag me! */
/* the four close planets to the home planet */
static int core_planets[4][4] =
{
  {7, 9, 5, 8,},
  {12, 19, 15, 16,},
  {24, 29, 25, 26,},
  {34, 39, 38, 37,},
};
/* the outside edge, going around in order */
static int front_planets[4][5] =
{
  {1, 2, 4, 6, 3,},
  {14, 18, 13, 17, 11,},
  {22, 28, 23, 21, 27,},
  {31, 32, 33, 35, 36,},
};

void cleanup();
void reset_inl();
int checkmess();
void inlmove();
int end_tourney();
int start_tourney();

extern char *addr_mess();


int
main(argc, argv)
   int             argc;
   char           *argv[];
{
   int i;

   srandom(time(NULL));

   getpath();
   openmem(1);
   readsysdefaults();

   if ((inl_log = fopen(N_INLLOG,"w+"))==NULL) {
	ERROR(1,("Could not open INL log file.\n"));
	exit(1);
   } 

   SIGNAL(SIGALRM, inlmove);             /*the def signal is needed - MK */
   if (!debug)
   {
     SIGNAL(SIGINT, cleanup);
     SIGNAL(SIGTERM, cleanup);
   }

   oldmctl = mctl->mc_current;
#ifdef nodef
   for (i = 0; i <= oldmctl; i++) {
      check_command(&messages[i]);
   }
#endif

   pmessage(0, MALL, inl_from, "###############################");
   pmessage(0, MALL, inl_from, "#  The INL robot has entered  #");
   pmessage(0, MALL, inl_from, "###############################");

   init_server();
   reset_inl();

   udt.it_interval.tv_sec = 0;        /* Robots move PERSEC times/sec */
   udt.it_interval.tv_usec = 1000000 / PERSEC;

   udt.it_value.tv_sec = 1;
   udt.it_value.tv_usec = 0;
   if (setitimer(ITIMER_REAL, &udt, 0) < 0) {
           perror("setitimer");
           exit(1);
   }

   /* allows robots to be forked by the daemon -- Evil ultrix bullshit */
   SIGSETMASK(0);

   while (1) {
        PAUSE(SIGALRM);
   }
}

void inl_freeze(void)
{
  int c;
  struct player *j;

  for (c=0; c < INLTEAM; c++)
    inl_teams[c].flags |= T_PAUSE;

  inl_stat.flags |= S_FREEZE;
  status->gameup |= (GU_PRACTICE | GU_PAUSED);

  for (j = firstPlayer; j <= lastPlayer; j++)
  {
    j->p_flags &= ~(PFSEEN);
    j->p_lastseenby = VACANT;  /* if left non-vacant the daemon might */
  }                            /* not reinitalize PFSEEN automaticly */

  pmessage(0, MALL, inl_from, "-------- Game is paused -------");

}

void inl_confine(void)
{
  struct player *j;

  for (j = firstPlayer; j <= lastPlayer; j++)
  {
    if (j->p_x < cbounds[j->p_team][0])
      j->p_x = cbounds[j->p_team][0];
    if (j->p_y < cbounds[j->p_team][1])
      j->p_y = cbounds[j->p_team][1];
    if (j->p_x > cbounds[j->p_team][2])
      j->p_x = cbounds[j->p_team][2];
    if (j->p_y > cbounds[j->p_team][3])
      j->p_y = cbounds[j->p_team][3];
  }
}

void inlmove()
{
  int c;

    /***** Start The Code Here *****/
 
    HANDLE_SIG(SIGALRM,inlmove);

#ifdef INLDEBUG
    ERROR(2,("Enter inlsmove\n"));
#endif

    inl_stat.ticks++;
    player_maint();                     /* update necessary stats and info */

    if (inl_stat.flags & S_COUNTDOWN ) 
	countdown(inl_stat.ticks,&inl_countdown);
    else if (! (inl_stat.ticks % (PERSEC*2))) /* no com. during countdown */
	checkmess();

    if (inl_stat.flags & S_CONFINE)
      inl_confine();

    if (!(inl_stat.flags & (S_TOURNEY | S_OVERTIME)) ||
	(inl_stat.flags & S_FREEZE ))
	 return;

    inl_stat.game_ticks++;

/* check for timeout */
    if (inl_stat.flags & S_TMOUT)
    {
      inl_stat.tmout_ticks++;
      if ((inl_stat.tmout_ticks > 1300) || all_alert(PFGREEN)
	  || ((inl_stat.tmout_ticks > 800) && all_alert(PFYELLOW)))
	                            /* This is a loose approximation
				       of the INL source code.. */
      {
	inl_stat.flags &= ~(S_TMOUT);
	inl_stat.tmout_ticks = 0;

	for (c=0; c < INLTEAM; c++)
	  inl_teams[c].flags &= ~(T_TIMEOUT);

	inl_freeze();
      }
    }

/*  printf("Setting tourn\n"); */
    status->tourn = 1;		/* paranoia? */
    if (!(inl_stat.game_ticks % PLANETFUSE))
      checkplanets();

/* check for sudden death overtime */
    if ((inl_stat.flags & S_OVERTIME) && (inl_stat.game_ticks % PERSEC))
      end_tourney();

/* display periodic countdown */
    if (!(inl_stat.game_ticks % TIMEFUSE))
      countdown(inl_stat.game_ticks, &inl_game);

#ifdef INLDEBUG
    ERROR(2,("	game ticks = %d\n", inl_stat.game_ticks));
#endif
}

player_maint()
{
#ifdef INLDEBUG
    ERROR(2,("Enter player_maint\n"));
#endif
}

int all_alert(int stat)
{
  struct player *j;

  for (j = firstPlayer; j <= lastPlayer; j++)
    if ((j->p_status == PALIVE) && !(j->p_flags & stat))
      return 0;

  return 1;
}

log(m)
struct message *m;
{
    time_t curtime;
    struct tm *tmstruct;
    int hour;
    int least = MBOMB;
    /* decide whether or not to log this message */
#ifdef nodef
    if (m->m_flags & MINDIV) return; /* individual message */
    if (!(m->m_flags & MGOD)) return;
    if ((m->m_flags & MGOD) > least) return;
#endif
    /*
    time(&curtime);
    tmstruct = localtime(&curtime);
    if (!(hour = tmstruct->tm_hour%12)) hour = 12;
    fprintf(inl_log,"%02d:%02d %-73.73s\n", hour, tmstruct->tm_min,
           m->m_data);
    */
    fprintf(inl_log,"%5d: %s\n",inl_stat.ticks,m->m_data);
}

checkmess()
{
   int 	shmemKey = PKEY;
   int i;

#ifdef INLDEBUG
    ERROR(2,("Enter checkmess\n"));
#endif

      /* make sure shared memory is still valid */
      if (shmget(shmemKey, SHMFLAG, 0) < 0) {
	 exit(1);
	 ERROR(2,("ERROR: Invalid shared memory\n"));

      }

    while (oldmctl!=mctl->mc_current) {
        oldmctl++;
        if (oldmctl==MAXMESSAGE) oldmctl=0;
        if (messages[oldmctl].m_flags & MINDIV) {
            if (messages[oldmctl].m_recpt == messages[oldmctl].m_from) {
		me = &players[messages[oldmctl].m_from];
                check_command(&messages[oldmctl]);
	    }
        } 
#ifdef nodef
	else if (messages[oldmctl].m_flags & MALL) {
            if (strstr(messages[oldmctl].m_data, "help") != NULL)
                pmessage(messages[oldmctl].m_from, MINDIV, 
		   addr_mess(messages[oldmctl].m_from),
                   "If you want help, send the message 'help' to yourself.");
        }
#endif
      log(&(messages[oldmctl]));
    }
}


checkplanets()
{
   int c;
   int size;
   int i;

#ifdef INLDEBUG
    ERROR(2,("Enter checkplanets\n"));
#endif

   size = sizeof(struct planet);

   for (c=0; c < MAXPLANETS; c++ ) {
	if (MCMP(&inl_planets[c], &planets[c], size) != 0) {	
	    /* Some planet information changed. Find out what it is and
	       report it. */

	    /* pl_no, & pl_flags should never change */
	    /* pl_x, pl_y, pl_name, pl_namelen should never change in INL */
	    /* pl_deadtime & pl_couptime should not be of any interest */

	    if (inl_planets[c].pl_owner != planets[c].pl_owner) {
		fprintf(inl_log,"PLANET: %s was taken by the %s from %s\n",
			inl_planets[c].pl_name, teamshort[planets[c].pl_owner],
			teamshort[inl_planets[c].pl_owner]);

	    /*  Keep team[x].planets up to date */
	      for (i=0; i < INLTEAM; i++)
	      {
		if (sides[inl_teams[i].side_index].flag
		    == inl_planets[c].pl_owner)
		  inl_teams[i].planets--;
		if (sides[inl_teams[i].side_index].flag
		    == planets[c].pl_owner)
		  inl_teams[i].planets++;
	      }

		inl_planets[c].pl_owner = planets[c].pl_owner; 
	    }
	    if (inl_planets[c].pl_armies != planets[c].pl_armies) {
		if (inl_planets[c].pl_armies > planets[c].pl_armies)
		    fprintf(inl_log,
			"PLANET: %s's armies have been reduced to %d\n",
			inl_planets[c].pl_name,
			planets[c].pl_armies);
		else 
		    fprintf(inl_log,
			"PLANET: %s's armies have increased to %d\n",
			inl_planets[c].pl_name,
			planets[c].pl_armies);
		inl_planets[c].pl_armies = planets[c].pl_armies;
	    }
	    if (inl_planets[c].pl_info != planets[c].pl_info) {
		int who, i;
	
		who = inl_planets[c].pl_info | planets[c].pl_info & 
		      ~(inl_planets[c].pl_info & planets[c].pl_info);
	
		for (i = 0; i < INLTEAM; i++) {
		    if (who & sides[inl_teams[i].side_index].flag)
		      fprintf(inl_log,
			"PLANET: %s has been touched by the %ss(%s)\n",
			inl_planets[c].pl_name, 
			sides[inl_teams[i].side_index].name,
			inl_teams[i].name);
		}
		inl_planets[c].pl_info = planets[c].pl_info;
	    }
	}
    }
}

int end_tourney()
{
  if ((inl_teams[HOME].planets > inl_teams[AWAY].planets+2)
       || (inl_teams[AWAY].planets > inl_teams[HOME].planets+2))
  {
    pmessage(0, MALL, inl_from, "---------- Game Over ----------");
    pmessage(0, MALL, inl_from, "Result: %i - %i - %i",
	     inl_teams[HOME].planets, inl_teams[AWAY].planets,
	     (20 - inl_teams[HOME].planets - inl_teams[AWAY].planets));
    status->tourn = 0;
    reset_inl();
  }

  if (inl_stat.flags & S_TOURNEY)
  {
    inl_stat.flags &= ~(S_TOURNEY | S_COUNTDOWN);
    inl_stat.flags |= S_OVERTIME;
    pmessage(0, MALL, inl_from, "---------- Overtime ----------");
    obliterate(0,KSHIP);

    inl_game.idx = 0;
    inl_game.end += inl_stat.overtime;
/*  inl_game.counts[0] = inl_stat.overtime / (PERMIN*2); */
    inl_game.message = "%i %s left in overtime";

  }
  else if (inl_game.end <= inl_stat.game_ticks)
  {
    pmessage(0, MALL, inl_from, 
	     "------ Game ran out of time without a winner ------");
    status->tourn = 0;
    reset_inl();
  }
}

void reset_inl()
{
  int c;

  /* Tourn off t-mode */
  status->gameup |= (GU_CHAOS | GU_PRACTICE);
  status->gameup &= ~(GU_PAUSED);
  
  inl_stat.ticks = 0;

  for (c=0; c < INLTEAM; c++) {
    inl_teams[c].flags = 0;		/* reset all flags */
  }

  inl_stat.start_armies = 17;
  inl_stat.change = 1;
  inl_stat.flags = S_PREGAME;
  inl_stat.ticks = 0;
  inl_stat.game_ticks = 0;
  inl_stat.tmout_ticks = 0;
  inl_stat.time = 0;
  inl_stat.overtime = 0;

  inl_teams[HOME].team = HOME;
  inl_teams[HOME].name = "home";
  inl_teams[HOME].t_name = "Home";
  inl_teams[HOME].captain = NONE;
  inl_teams[HOME].side = HOMETEAM;
  inl_teams[HOME].side_index = NOT_CHOOSEN;
  inl_teams[HOME].start_armies = 17;
  inl_teams[HOME].time = 90;
  inl_teams[HOME].overtime = 30;
  inl_teams[HOME].flags = 0;
  inl_teams[HOME].tmout = 1;
  inl_teams[HOME].planets = 10;

  inl_teams[AWAY].team = AWAY;
  inl_teams[AWAY].name = "away";
  inl_teams[AWAY].t_name = "Away";
  inl_teams[AWAY].captain = NONE;
  inl_teams[AWAY].side = AWAYTEAM;
  inl_teams[AWAY].side_index = NOT_CHOOSEN;
  inl_teams[AWAY].start_armies = 17;
  inl_teams[AWAY].time = 90;
  inl_teams[AWAY].overtime = 30;
  inl_teams[AWAY].flags = 0;
  inl_teams[AWAY].tmout = 1;
  inl_teams[AWAY].planets = 10;

  /* Set player queues back to standard starting teams */
  queues[QU_HOME].tournmask = FED;
  queues[QU_AWAY].tournmask = ROM;
  queues[QU_HOME_OBS].tournmask = FED;
  queues[QU_AWAY_OBS].tournmask = ROM;

  doResources(1);

  obliterate(1, KSHIP);

}

init_server()
{
   register        i;
   register struct planet *j;

   /* Fix planets */
   oldplanets = (struct planet *) malloc(sizeof(struct planet) * MAXPLANETS);
   MCOPY(planets, oldplanets, sizeof(struct planet) * MAXPLANETS);

   /* Dont change the pickup queues around - just close them. */
#ifdef nodef
   /* Split the Waitqueues */
   /* Change the regular port to an observer port */
   queues[QU_PICKUP].tournmask     = (HOMETEAM | AWAYTEAM);
#endif

   /* Nah, just close them down.. */
   queues[QU_PICKUP].q_flags       &= ~(QU_OPEN);
   queues[QU_PICKUP_OBS].q_flags   &= ~(QU_OPEN);

   /* these already set in queue.c - assume they are correct */
#ifdef nodef
   /* Ensure some inl queue initialization */
   queues[QU_HOME].max_slots  = TEAMSIZE;
   queues[QU_HOME].tournmask  = HOMETEAM;
   queues[QU_AWAY].max_slots  = TEAMSIZE;
   queues[QU_AWAY].tournmask  = AWAYTEAM;
   queues[QU_HOME_OBS].max_slots  = TESTERS;
   queues[QU_HOME_OBS].tournmask  = HOMETEAM;
   queues[QU_HOME_OBS].low_slot   = MAXPLAYER-TESTERS;
   queues[QU_AWAY_OBS].max_slots  = TESTERS;
   queues[QU_AWAY_OBS].tournmask  = AWAYTEAM;
   queues[QU_AWAY_OBS].low_slot   = MAXPLAYER-TESTERS;
#endif

   /* Open INL ports */
   queues[QU_HOME].q_flags   |= QU_OPEN;
   queues[QU_HOME].free_slots = queues[QU_HOME].max_slots;
   queues[QU_AWAY].q_flags   |= QU_OPEN;
   queues[QU_AWAY].free_slots = queues[QU_AWAY].max_slots;
   queues[QU_HOME_OBS].q_flags   |= QU_OPEN;
   queues[QU_HOME_OBS].free_slots = queues[QU_HOME_OBS].max_slots;
   queues[QU_AWAY_OBS].q_flags   |= QU_OPEN;
   queues[QU_AWAY_OBS].free_slots = queues[QU_AWAY_OBS].max_slots;

   status->tourn = 0;

   obliterate(1, KSHIP);

   /* If players are in game select teams alternately */
   for (i = 0; i<(MAXPLAYER-TESTERS); i++) {
	/* Let's deactivate the pickup slots and move pickup observers
	   to the INL observer slots */
#ifdef nodef
        /* Don't change any pickup observers */
        if (players[i].p_status == POBSERV) continue;     
#endif
	if (players[i].p_status != PFREE)
	{
	  queues[players[i].w_queue].free_slots++;

	  if (i%2)
	    players[i].w_queue = (players[i].p_status == POBSERV)
	      ? QU_HOME_OBS : QU_HOME;
	  else
	    players[i].w_queue = (players[i].p_status == POBSERV)
	      ? QU_AWAY_OBS : QU_AWAY;

	  queues[players[i].w_queue].free_slots--;
	}
    }

   /* dont set all the info - just what is neccessary */
    queues[QU_PICKUP].free_slots = 0;
    queues[QU_PICKUP_OBS].free_slots = 0;
#ifdef nodef
    queues[QU_PICKUP].low_slot = MAXPLAYER-TESTERS;
    queues[QU_PICKUP].max_slots = TESTERS;
    queues[QU_PICKUP].high_slot = MAXPLAYER;
#endif
}


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

    SIGNAL(SIGALRM, SIG_IGN);

    status->gameup &= ~(GU_CHAOS | GU_PRACTICE);
    status->gameup &= ~(GU_PAUSED);

    /* restore galaxy */
    MCOPY(oldplanets, planets, sizeof(struct planet) * MAXPLANETS);

    /* Dont mess with the queue information - it is set correctly in queue.c */
#ifdef nodef
    /* restore old wait queue */
    queues[QU_PICKUP].tournmask=ALLTEAM;
#endif

    /* Open Pickup ports */
    queues[QU_PICKUP].q_flags |= QU_OPEN;
    queues[QU_PICKUP].free_slots = queues[QU_PICKUP].max_slots;
    queues[QU_PICKUP_OBS].q_flags |= QU_OPEN;
    queues[QU_PICKUP_OBS].free_slots = queues[QU_PICKUP_OBS].max_slots;

    /* Close INL ports */
    queues[QU_HOME].q_flags &= ~(QU_OPEN);
    queues[QU_AWAY].q_flags &= ~(QU_OPEN);
    queues[QU_HOME_OBS].q_flags &= ~(QU_OPEN);
    queues[QU_AWAY_OBS].q_flags &= ~(QU_OPEN);
    /* Set player queues back to standard starting teams */
    queues[QU_HOME_OBS].tournmask = HOMETEAM;
    queues[QU_AWAY_OBS].tournmask = AWAYTEAM;

    for (i = 0, j = &players[i]; i < MAXPLAYER; i++)
    {
      j = &players[i];
      if (j->p_status != PFREE)
      {
	queues[j->w_queue].free_slots++;
	if (players[i].p_status == POBSERV)
	  j->w_queue = QU_PICKUP_OBS;
	else
	  j->w_queue = QU_PICKUP;
	queues[j->w_queue].free_slots--;
      }
      if (j->p_status != PALIVE) continue;
      getship(&(j->p_ship), j->p_ship.s_type);
    }

    queues[QU_HOME].free_slots=0;
    queues[QU_AWAY].free_slots=0;
    queues[QU_HOME_OBS].free_slots=0;
    queues[QU_AWAY_OBS].free_slots=0;

#ifdef nodef
    queues[QU_PICKUP].free_slots += MAXPLAYER-TESTERS;
    queues[QU_PICKUP].low_slot = 0;
    queues[QU_PICKUP].high_slot = MAXPLAYER-TESTERS;
    queues[QU_PICKUP].max_slots = MAXPLAYER-TESTERS;
#endif

    pmessage(0, MALL, inl_from, "##########################");
    pmessage(0, MALL, inl_from, "#  The inl robot has left");
    pmessage(0, MALL, inl_from, "#  INL game is now over. ");
    pmessage(0, MALL, inl_from, "##########################");

    /* Flushing messages */
    checkmess();
    close(N_INLLOG);
    exit(0);
}

start_countdown()
{
    int c;
    struct player *j;

    inl_stat.change = 0;

    inl_teams[HOME].side = sides[inl_teams[HOME].side_index].flag;
    inl_teams[AWAY].side = sides[inl_teams[AWAY].side_index].flag;

    /* Set the queues so players go to correct side */
    queues[QU_HOME].tournmask = inl_teams[HOME].side;
    queues[QU_AWAY].tournmask = inl_teams[AWAY].side;
    queues[QU_HOME_OBS].tournmask = inl_teams[HOME].side;
    queues[QU_AWAY_OBS].tournmask = inl_teams[AWAY].side;

    /* Nah.. just deactivate pickup queus.. */
#ifdef nodef
    queues[QU_PICKUP].tournmask = inl_teams[HOME].side | inl_teams[AWAY].side;
    queues[QU_PICKUP_OBS].tournmask = 
      inl_teams[HOME].side | inl_teams[AWAY].side;
#endif

    obliterate(2, KSHIP);

    pmessage(0, MALL, inl_from, "Teams are   %s (%s): %s,    %s (%s): %s",
	 inl_teams[HOME].t_name, 
	 inl_teams[HOME].name,
	 sides[inl_teams[HOME].side_index].name,
	 inl_teams[AWAY].t_name, 
	 inl_teams[AWAY].name,
	 sides[inl_teams[AWAY].side_index].name);
    pmessage(0, MALL, inl_from, " ");
    pmessage(0, MALL, inl_from, "Teams chosen.  Game will start in 1 minute.");
    pmessage(0, MALL, inl_from, 
		"----------- Game will start in 1 minute -------------");
    pmessage(0, MALL, inl_from, 
		"----------- Game will start in 1 minute -------------");

    inl_stat.flags = S_COUNTDOWN;
    inl_countdown.idx = 0;
    inl_countdown.end = inl_stat.ticks+INLSTARTFUSE;
    inl_countdown.action = start_tourney;
    inl_countdown.message = "Game start in %i %s";

}


start_tourney()
{
    int c;
    struct player* j;
    struct timeval tv;
    struct tm *tp;
    char *ap;
    char tmp[MSG_LEN];

    pmessage(0, MALL, inl_from, " ");

    pmessage(0, MALL, inl_from, 
	"INL Tournament starting now. %s(%s) vs. %s(%s).",
	 inl_teams[HOME].t_name, 
	 inl_teams[HOME].name,
	 inl_teams[AWAY].t_name, 
	 inl_teams[AWAY].name);

    pmessage(0, MALL, inl_from, " ");

    gettimeofday (&tv, (struct timezone *) 0);

    fprintf(inl_log, "TIME: Game started at %d seconds\n", tv.tv_sec);

    tp = localtime (&tv.tv_sec);
    ap = asctime (tp);

    strncpy (tmp, ap + 4, 15);
    *(tmp + 15) = '\0';
    pmessage (0, MALL, inl_from, "%s is the starting time of t-mode play.", 
		tmp);

    doResources(0);

    inl_planets = (struct planet *) malloc(sizeof(struct planet) * MAXPLANETS);
/*    MCOPY(planets, oldplanets, sizeof(struct planet) * MAXPLANETS); */
    MCOPY(planets, inl_planets, sizeof(struct planet) * MAXPLANETS);

    inl_stat.flags |= S_TOURNEY;
    inl_stat.flags &= ~(S_PREGAME | S_COUNTDOWN | S_CONFINE);

    obliterate(1,TOURNSTART);

    inl_stat.time = inl_teams[0].time * PERMIN;
    inl_stat.overtime = inl_teams[0].overtime * PERMIN;
    inl_stat.game_ticks = 0;

    status->gameup &= ~(GU_CHAOS | GU_PRACTICE);
#ifdef DEBUG
	printf("Setting tourn\n");
#endif
    status->tourn = 1;
    inl_game.idx=0;
    inl_game.end= inl_stat.time;
/*    inl_game.counts[0] = inl_stat.time / ( PERMIN * 2); */
    inl_game.message = "%i %s left in regulation time";
}


obliterate(wflag, kreason)
     int wflag;
     char kreason;
{
  /* 0 = do nothing to war status, 1= make war with all, 2= make peace with all */
  struct player *j;
  int i, k;

  /* clear torps and plasmas out */
  MZERO(torps, sizeof(struct torp) * MAXPLAYER * (MAXTORP + MAXPLASMA));
  for (j = firstPlayer; j<=lastPlayer; j++) {
    if (j->p_status == PFREE)
      continue;
    j->p_status = PEXPLODE;
    j->p_whydead = kreason;
    if (j->p_ship.s_type == STARBASE)
      j->p_explode = 2 * SBEXPVIEWS ;
    else
      j->p_explode = 10 ;
    j->p_ntorp = 0;
    j->p_nplasmatorp = 0;
    if (wflag == 1)
      j->p_hostile = (FED | ROM | ORI | KLI);         /* angry */
    else if (wflag == 2)
      j->p_hostile = 0;       /* otherwise make all peaceful */
    j->p_war = (j->p_swar | j->p_hostile);
  }
}


countdown(counter,cnt)
int counter;
Inl_countdown *cnt;
{
  int i = 0;
  int j = 0;
  char *ms;

  if (cnt->end - cnt->counts[cnt->idx]*cnt->unit > counter)
    return;

  while ((cnt->idx != cnt->act) && 
    (cnt->end - cnt->counts[cnt->idx+1]*cnt->unit <= counter))
  {
    cnt->idx++;
  }

  i = cnt->counts[cnt->idx];

  if (i > 60)
  {
    i = i / 60;
    j = 2;
  }
  if (i == 1)
    j++;

  pmessage(0, MALL, inl_from, cnt->message, i, time_msg[j]);
  if (cnt->idx++ == cnt->act) (*(cnt->action))();

}

doResources(startup)
int startup;
{
  int i, j, k, which;

  /* this is all over the fucking place :-) */
  for (i = 0; i <= MAXTEAM; i++)
    {
      teams[i].s_turns = 0;
    }
  if (startup)
    {
      MCOPY (pdata, planets, sizeof (pdata));

      for (i = 0; i < MAXPLANETS; i++)
        {
          planets[i].pl_info = ALLTEAM;
        }

      for (i = 0; i < 4; i++)
        {
          /* one core AGRI */
          planets[core_planets[i][random () % 4]].pl_flags |= PLAGRI;

          /* one front AGRI */
          which = random () % 2;
          if (which)
            {
              j = random () % 2;
              planets[front_planets[i][j]].pl_flags |= PLAGRI;

              /* give fuel to planet next to agri (hde) */
              planets[front_planets[i][!j]].pl_flags |= PLFUEL;

              /* place one repair on the other front */
              planets[front_planets[i][(random () % 3) + 2]].pl_flags |= PLREPAIR;

              /* place 2 FUEL on the other front */
              for (j = 0; j < 2; j++)
                {
                  do
                    {
                      k = random () % 3;
                    }
                  while (planets[front_planets[i][k + 2]].pl_flags & PLFUEL);
                  planets[front_planets[i][k + 2]].pl_flags |= PLFUEL;
                }
            }
          else
            {
              j = random () % 2;
              planets[front_planets[i][j + 3]].pl_flags |= PLAGRI;
              /* give fuel to planet next to agri (hde) */
              planets[front_planets[i][(!j) + 3]].pl_flags |= PLFUEL;

              /* place one repair on the other front */
              planets[front_planets[i][random () % 3]].pl_flags |= PLREPAIR;

              /* place 2 FUEL on the other front */
              for (j = 0; j < 2; j++)
                {
                  do
                    {
                      k = random () % 3;
                    }
                  while (planets[front_planets[i][k]].pl_flags & PLFUEL);
                  planets[front_planets[i][k]].pl_flags |= PLFUEL;
                }
            }

          /* drop one more repair in the core 
		(home + 1 front + 1 core = 3 Repair) */

          planets[core_planets[i][random () % 4]].pl_flags |= PLREPAIR;

          /* now we need to put down 2 fuel (home + 2 front + 2 = 5 fuel) */

          for (j = 0; j < 2; j++)
            {
              do
                {
                  k = random () % 4;
                }
              while (planets[core_planets[i][k]].pl_flags & PLFUEL);
              planets[core_planets[i][k]].pl_flags |= PLFUEL;
            }
        }
    }
  else
    {
      for (i = 0; i < MAXPLANETS; i++)
        {
          planets[i].pl_info = pdata[i].pl_info;
          planets[i].pl_owner = pdata[i].pl_owner;
          planets[i].pl_armies = inl_stat.start_armies;
        }
    }
}
