static char *rcsid = "$Header: /plaid/homes/zeus/Blind-2.47/RCS/turn.c,v 2.47 1998/04/15 21:34:17 zeus Exp zeus $";

/*
 * $Log: turn.c,v $
 * Revision 2.47  1998/04/15 21:34:17  zeus
 * *** empty log message ***
 *
 * Revision 2.46.0.1  1997/05/27 21:05:23  zeus
 * Revision 2.46  1997/04/18 12:06:12  zeus
 * Revision 2.45  1996/12/31  23:40:54  zeus
 * Revision 2.44  1995/12/31  19:45:18  zeus
 * Revision 2.43  1995/03/20  01:43:09  zeus
 * Revision 2.42  1994/05/17  13:43:15  bampton
 * Revision 2.41  1994/04/08  03:11:28  bampton
 * Revision 2.40  1994/03/09  20:22:55  bampton
 * Revision 2.39  1993/10/28  22:31:20  bampton
 * Revision 2.38  1993/09/27  17:15:54  bampton
 * Revision 2.37  1993/09/07  20:50:32  bampton
 * Revision 2.34  1993/08/09  23:06:20  bampton
 * Revision 2.33  1993/08/03  23:10:13  bampton
 * Revision 2.30  1993/07/14  14:59:26  bampton
 * Revision 0.0  1993/07/14  13:42:30  bampton RCS prototype.
 */

#define NOTIMEB
#include "common.h"
#include "prototypes.h"
#include "turn.h"
#include "turn-g.h"
#include "battle-g.h"
#include "misc-g.h"
#include "speed.h"
#include "options.h"

#ifdef SMARTC
#include "cmds.h"
#include "exit.h"
#include "enterturn.h"
#include "enterturn-g.h"
#endif


void turn_rcsid (void);

void
turn_rcsid (void)
{
  printf ("%s\n", rcsid);
}


/* Magic hack to get forecast code to work... */

#ifndef FORECAST

#ifdef PREPROC
#define NOPREPROC
#undef VERBOSE
#endif

#endif

#ifndef NOPREPROC
extern player *players;
extern planet *planets;
extern battle *battles;
extern bombing *bombings;
extern shiptype *shiptypes;
extern fleetname *fleets;
extern int turn;
extern int turn_run;
extern int nplanets;
extern tmppname *tmpname;

#if SPEED&2
int seenlist[MAXPLAN];

#else
/* this is a hack, gotta be a better way to do it */
/* yes, I should malloc() it */
int seenlist[1000];

#endif

#ifdef FORECAST
void
build_seen_list (player * P)
{
  int x;
  planet *p;

  for (x = 0; x <= nplanets; x++)
    seenlist[x] = 0;
  /* Yes, x should be 1, not 0 */
  for (p = planets, x = 1; p; p = p->next, x++)
  {
    seenlist[x] = canseeplanet (P, p, 0);
  }
}
#endif
void
loadphase (void)
{
  player *P;
  group *g, *g2;
  int i;
  planet *p;
  double qty, shipspace, availspace;

  for (p = planets; p; p = p->next)
    if ((P = p->owner) != 0)
    {
      if (p->routes[CG_COL])
        for (g = P->groups; g; g = g->next)
        {
          if (g->where == p && g->type->cargo && g->dist == 0.0 &&
              g->type->drive > 0.01 && !g->fleet && g->ships)
          {
            if (g->loadtype == CG_EMPTY && p->col)
            {
              qty = p->col;
              shipspace = cargospace (g);
              availspace = g->ships * shipspace;
              if (qty > availspace)
                qty = availspace;
              p->col -= qty;
              availspace -= qty;
              i = availspace / shipspace;
              if (i)
              {
                g->ships -= i;
                g2 = alloc (sizeof (group));
                *g2 = *g;
                g2->alias = NULL;
                addlist (&P->groups, g2);
                g2->ships = i;
              }
              g->loadtype = CG_COL;
              g->load = qty / g->ships;
            }
            if (g->loadtype == CG_COL)
              Send (g, p->routes[CG_COL]);
          }
        }
      if (p->routes[CG_CAP])
        for (g = P->groups; g; g = g->next)
        {
          if (g->where == p && g->type->cargo && g->dist == 0.0 &&
              g->type->drive > 0.01 && !g->fleet && g->ships)
          {
            if (g->loadtype == CG_EMPTY && p->cap)
            {
              qty = p->cap;
              shipspace = cargospace (g);
              availspace = g->ships * shipspace;
              if (qty > availspace)
                qty = availspace;
              p->cap -= qty;
              availspace -= qty;
              i = availspace / shipspace;
              if (i)
              {
                g->ships -= i;
                g2 = alloc (sizeof (group));
                *g2 = *g;
                addlist (&P->groups, g2);
                g2->ships = i;
              }
              g->loadtype = CG_CAP;
              g->load = qty / g->ships;
            }
            if (g->loadtype == CG_CAP)
              Send (g, p->routes[CG_CAP]);
          }
        }
      if (p->routes[CG_MAT])
        for (g = P->groups; g; g = g->next)
          if (g->where == p && g->type->cargo && g->dist == 0.0 &&
              g->type->drive > 0.01 && !g->fleet && g->ships)
          {
            if (g->loadtype == CG_EMPTY && p->mat)
            {
              qty = p->mat;
              shipspace = cargospace (g);
              availspace = g->ships * shipspace;
              if (qty > availspace)
                qty = availspace;
              p->mat -= qty;
              availspace -= qty;
              i = availspace / shipspace;
              if (i)
              {
                g->ships -= i;
                g2 = alloc (sizeof (group));
                *g2 = *g;
                addlist (&P->groups, g2);
                g2->ships = i;
              }
              g->loadtype = CG_MAT;
              g->load = qty / g->ships;
            }
            if (g->loadtype == CG_MAT)
              Send (g, p->routes[CG_MAT]);
          }
      if (p->routes[CG_EMPTY])
        for (g = P->groups; g; g = g->next)
        {
          if (g->where == p && g->type->cargo && g->dist == 0.0 &&
              g->type->drive > 0.01 && !g->fleet && g->ships)
            if (g->loadtype == CG_EMPTY)        /* BUGFIX 3/19/96 */

            {
              Send (g, p->routes[CG_EMPTY]);
            }
        }
    }
}

#ifndef FORECAST
void
interceptphase (void)
{
  int j;
  double maxmass, maxdist, *v, distm;
  player *P, *P2;
  group *g, *g2;
  planet *p, *p2;

  v = alloc (nplanets * sizeof (double));

  for (P = players; P; P = P->next)
  {
    if (P->opts1 & SHORTINT)
      distm = 1.0;
    else
      distm = 2.0;
    for (g = P->groups; g; g = g->next)
    {
      if (g->dist == INTERCEPT) /* Bugfix to deal with upgrade, HJB */
      {
        maxdist = distm * group_speed (g->tech, g->type, shipmass (g));
        /* fast group in fleet bugfix */
        if (g->fleet)
          maxdist = distm * g->fleet->fleetspeed;

        p = g->from;
        memset (v, 0, nplanets * sizeof (double));

        /* fabs() stuff to work around a roundoff problem */
        for (P2 = players; P2; P2 = P2->next)
          if (P2 != P)
            for (g2 = P2->groups; g2; g2 = g2->next)
              if (g2->from == p && g2->where != p &&
                  fabs (g2->dist - dist (p, g2->where)) < ALMOSTZERO &&
                  dist (g->where, g2->where) < maxdist)
                v[ptonum (planets, g2->where)] +=
                  g2->ships * shipmass (g2);
        maxmass = 0;
        for (j = 1, p2 = planets; j != nplanets; j++, p2 = p2->next)
          if ((v[j] > maxmass) && (canseeplanet (P, p2, 0)))
          {
            maxmass = v[j];
            p = p2;
          }
        Send (g, p);
      }
    }
  }
  free (v);
}
#else
void
interceptphase (void)
{
  player *P;
  group *g;

  for (P = players; P; P = P->next)
  {
    if (abs (P->lastorders) == turn + 1)
      break;
  }
  if (P)
  {
    for (g = P->groups; g; g = g->next)
    {
      if (g->dist == INTERCEPT) /* Bugfix to deal with upgrade, HJB */
      {
        Send (g, g->from);
      }
    }
  }
}
#endif

void
fleetphase (void)
{
  player *P;
  fleetname *fl, *fl2;
  group *g;
  double shipspeed;
  planet *p;
  int hasships;

  for (fl = fleets; fl; fl = fl2)
  {
    fl2 = fl->next;             /* BUGFIX */
    hasships = 0;
    p = NULL;
    fl->fleetspeed = 1000000.0;
    P = fl->owner;
    for (g = P->groups; g; g = g->next)
    {
      if (g->fleet == fl)
      {
        hasships = 1;
        /* Second or later group in this fleet, so sanity check */
        if (p)
        {

#ifndef PREPROC
          if (g->where != p)    /* Give the GM some clue about the offender */
          {
            fprintf (stderr, "Fleet insanity: Who:%s Which:%s Where %s,%s\n",
                     P->name, fl->name, p->name, g->where->name);
          }
#endif

          assert (g->where == p);       /* Groups from fleet in 2 locations! */
        }
        else
        {
          p = g->where;
        }
        shipspeed = group_speed (g->tech, g->type, shipmass (g));
        if (shipspeed < fl->fleetspeed)
          fl->fleetspeed = shipspeed;
      }
    }
    if (!hasships)
      removelist (&fleets, fl);
  }
}

void
movephase (void)
{
  player *P;
  group *g;

  for (P = players; P; P = P->next)
    for (g = P->groups; g; g = g->next)
    {
      if (g->fleet && (g->dist < 0.0))
        g->dist = 0.0;
      if (g->fleet)
        g->dist -= g->fleet->fleetspeed;
      /* Bug with upgrades and stationary fleets */
      else
        g->dist -= group_speed (g->tech, g->type, shipmass (g));
      if (g->dist < 0.0 + ROUNDOFF)     /* ~ 0.001 LY */
      {
        g->from = g->where;
        g->dist = 0.0;          /* This takes care of upgrade & overshoot
                                 * problems */
      }
    }
}

/* Unload iff, route goes from p to p2, and group is at p2 with cargo,
   and it isn't an alien planet[col only]
   OR
   autounload is set, we own the planet, and we've got ships there with
   cargo */

void
unloadphase (void)
{
  planet *p, *p2;
  group *g;
  register int i;

#ifdef FORECAST
  player *PP;

  for (PP = players; PP; PP = PP->next)
    if (abs (PP->lastorders) > turn)
      break;
#endif

  for (p = planets; p; p = p->next)
    if (p->owner)
      for (i = 0; i < CG_EMPTY; i++)
      {
        p2 = p->routes[i];
        for (g = p->owner->groups; g; g = g->next)
        {

#ifdef FORECAST
          /* Forecast, so do _NOT_ check for size 0 world, or being owned. */
          if (p->owner == PP)
            if ((g->where == p2 && g->dist == 0.0 && g->loadtype == i &&
                 g->ships)
            /* GE: change: cannot unload onto size 0 systems */
                ||
                ((p->owner->opts2 & AUTOUNLOAD) && (g->where == p) &&
                 (g->dist == 0.0) && (g->ships) && g->loadtype != CG_EMPTY))
#else

          if ((g->where == p2 && g->dist == 0.0 && g->loadtype == i &&
               g->ships &&      /* To deal with routes to alien systems: */
               !(g->loadtype == CG_COL && g->where->owner &&
                 g->where->owner != p->owner && p->owner)
               && p2->size > ALMOSTZERO)
          /* GE: change: cannot unload onto size 0 systems */
              ||
              ((p->owner->opts2 & AUTOUNLOAD) && (g->where == p) &&
               (g->dist == 0.0) && (g->ships) && g->loadtype != CG_EMPTY))
#endif

          {
            unloadgroup (g, p->owner);
          }                     /* end of: if gp at planet, planet >0, etc */
        }
      }                         /* end of: for loop over groups */
}

double
colinc (planet * p)
{
  double ind, popinc, extrapop, inccol, matdemand, inddemand;

  ind = effective_ind (p);
  popinc = p->pop * POPINC;
  extrapop = p->size - p->pop;
  if (extrapop > popinc)
    extrapop = popinc;
  p->pop += extrapop;
  ind += min (p->pop - p->ind,
              p->cap * INDFROMCAP);     /* include new CAP->new IND */
  popinc -= extrapop;
  inccol = popinc / POPPERCOL;
  matdemand = inccol * MATPERCOL;
  if (matdemand > p->mat)
    matdemand = p->mat;
  if (matdemand > ind * MATPERCOL / INDPERCOL)
    matdemand = ind * MATPERCOL / INDPERCOL;
  inccol -= matdemand / MATPERCOL;
  p->col += matdemand / MATPERCOL;
  p->mat -= matdemand;
  ind -= matdemand / MATPERCOL * INDPERCOL;
  matdemand = inccol * MATPERCOL;
  if (p->resources > 0)
    inddemand = matdemand * (INDPERCOL / MATPERCOL + 1 / p->resources);
  else
    inddemand = matdemand * (INDPERCOL / MATPERCOL + 1 / ALMOSTZERO);

  if (inddemand > ind)
  {
    matdemand *= ind / inddemand;
    inddemand = ind;
  }
  ind -= inddemand;
  p->col += matdemand / MATPERCOL;
  ind += p->inprogress;

  assert ((ind - p->spent) > -0.001);   /* catch round off error */
  ind -= p->spent;
  if (ind < 0.0)
    ind = 0.0;                  /* make sure we have no round off error! */
  p->spent = 0.0;

  p->inprogress = 0.0;
  return ind;
}

void
producephase (void)
{
  planet *p;
  double ind, shipcost, matdemand, totcost;
  shiptype *T;
  player *P;
  int inships;
  group *g;

#ifdef FORECAST
  player *PP;

  for (PP = players; PP; PP = PP->next)
    if (abs (PP->lastorders) > turn)
      break;
#endif

  for (p = planets; p; p = p->next)

#ifdef FORECAST
    if (p->owner && p->producing == PR_SHIP && p->owner == PP)
#else
    if (p->owner && p->producing == PR_SHIP)
#endif

    {
      ind = colinc (p);
      T = p->producingshiptype;

#ifdef PARTTECH
      shipcost = downgrade_cost (p->owner, T, p);
#else
      shipcost = typemass (T);
#endif

      totcost = shipcost * INDPERSHIP;
      if (shipcost > p->mat)
      {
        totcost += ((shipcost - p->mat) / p->resources);
      }
      inships = 0;
      while (ind + ROUNDOFF >= totcost)
      {
        inships++;
        ind -= totcost;
        p->mat -= shipcost;
        if (p->mat < 0.0)
          p->mat = 0.0;
        totcost = shipcost * INDPERSHIP;
        if (shipcost > p->mat)
        {
          totcost = shipcost * INDPERSHIP +
            ((shipcost - p->mat) / p->resources);
        }
      }

      p->inprogress = ind;
      if (inships)
      {                         /* No point in creating an empty group */
        g = alloc (sizeof (group));
        g->ships = inships;
        g->type = T;
        g->tech = p->owner->tech;

#ifdef PARTTECH
        /* Clobber default techs for group, if planet set to lower lvl */
        if (p->drive != 0.0)
          g->tech.drive = p->drive;
        if (p->guns != 0.0)
          g->tech.guns = p->guns;
        if (p->shields != 0.0)
          g->tech.shields = p->shields;
        if (p->cargo != 0.0)
          g->tech.cargo = p->cargo;
#endif

        if (!g->type->drive)
          g->tech.drive = 0.0;
        if (!g->type->nguns)
          g->tech.guns = 0.0;
        if (!g->type->shields)
          g->tech.shields = 0.0;
        if (!g->type->cargo)
          g->tech.cargo = 0.0;
        g->load = 0.0;
        g->loadtype = CG_EMPTY;
        g->from = g->where = p;
        g->dist = 0.0;
        T->numbuilt += inships;
        g->fleet = NULL;
        addlist (&p->owner->groups, g);
      }
    }
  for (p = planets; p; p = p->next)

#ifdef FORECAST
    if (p->owner && p->producing != PR_SHIP && p->owner == PP)
#else
    if (p->owner && p->producing != PR_SHIP)
#endif

    {
      ind = colinc (p);
      P = p->owner;
      switch (p->producing)
      {
      case PR_CAP:
        matdemand = ind / INDPERCAP;
        if (matdemand > p->mat)
          matdemand = p->mat;
        ind -= matdemand * INDPERCAP;
        p->cap += matdemand;    /* ? */
        p->mat -= matdemand;
        if (p->resources > 0)
          matdemand = ind / (INDPERCAP + 1 / p->resources);
        else
          matdemand = ind / (INDPERCAP + 1 / ALMOSTZERO);
        p->cap += matdemand;
        break;
      case PR_MAT:
        p->mat += ind * p->resources;
        break;
      case PR_DRIVE:
        P->tech.drive += ind / INDPERRESEARCH;
        break;
      case PR_GUNS:
        P->tech.guns += ind / INDPERRESEARCH;
        break;
      case PR_SHIELDS:
        P->tech.shields += ind / INDPERRESEARCH;
        break;
      case PR_CARGO:
        P->tech.cargo += ind / INDPERRESEARCH;
        break;
      default:
        assert (0);
      }
    }
  for (p = planets; p; p = p->next)
  {
    double indinc = p->pop - p->ind;

    if (indinc > (p->cap * INDFROMCAP))
      indinc = (p->cap * INDFROMCAP);
    /* cap mod */
    p->cap -= indinc / INDFROMCAP;
    p->ind += indinc;
  }
}

void
joinphase (void)
{
  player *P;
  group *g, *g2, *g3;

  for (P = players; P; P = P->next)
  {
    for (g = P->groups; g;)
    {
      if (!g->ships)            /* Remove shipless groups */
      {
        g2 = g->next;
        removelist (&P->groups, g);
        g = g2;
      }
      else
        /* Still has units, try to merge */
      {
        for (g2 = g; g2;)       /* g rather than g->next to avoid End of List */
        {
          if (g != g2 &&
              g->fleet == g2->fleet &&
              g->type == g2->type &&
              g->tech.drive == g2->tech.drive &&
              g->tech.guns == g2->tech.guns &&
              g->tech.shields == g2->tech.shields &&
              g->tech.cargo == g2->tech.cargo &&
              g->loadtype == g2->loadtype &&
              g->load == g2->load &&
              g->from == g2->from &&    /* Bugfix per k.pankhurst@ic.ac.uk */
              g->where == g2->where &&
              g->dist == g2->dist)
          {
            g->ships += g2->ships;
            g3 = g2->next;
            removelist (&P->groups, g2);
            g2 = g3;
          }
          else
            g2 = g2->next;
        }
        g = g->next;
      }
    }
  }
}

#if SPEED&4
void
sortphase (void)
{
  group *g, *g2, *prev;
  player *P;
  group *glist[MAXPLAN];
  int idx;
  int flag;
  group *gflist[MAXPLAN];
  fleetname *fl;

  for (P = players; P; P = P->next)

#ifdef PREPROC
    /* Sorting other player's groups in the preprocessor is pointless... */
  {
    if (abs (P->lastorders) > turn)
      break;                    /* We have a match */
  }
  if (P == NULL)
    P = players;                /* This shouldn't happen unless noone submitted orders */
#endif

  {
    if ((P->opts2 & SORTGROUPS))
    {
      for (idx = 0; idx < MAXPLAN; idx++)
      {
        glist[idx] = NULL;
        gflist[idx] = NULL;
      }

      /* Break every group off into an array, index based upon
         planet number, groups in fleets go into a separate array */
      for (g = P->groups; g; g = g->next)
      {
        idx = atoi (g->where->num);
        if (g->fleet != NULL)
        {
          if (gflist[idx] == NULL)
          {
            gflist[idx] = alloc (sizeof (group));
            *gflist[idx] = *g;
            gflist[idx]->next = NULL;
          }
          else
          {
            g2 = alloc (sizeof (group));
            *g2 = *g;
            addlist (gflist[idx], g2);
          }
        }
        else
        {
          if (glist[idx] == NULL)
          {
            glist[idx] = alloc (sizeof (group));
            *glist[idx] = *g;
            glist[idx]->next = NULL;
          }
          else
          {
            g2 = alloc (sizeof (group));
            *g2 = *g;
            g2->next = NULL;    /* Purify */
            g2->alias = NULL;   /* Purify */
            addlist (glist[idx], g2);
          }
        }
      }
      for (fl = fleets; fl; fl = fl->next)
        if (fl->owner == P)
        {
          flag = 1;
          for (idx = 0; idx < nplanets && flag; idx++)
          {
            if (gflist[idx] != NULL)
            {
              for (g = gflist[idx]; g; g = g->next)
              {
                if (g->fleet == fl)
                {
                  /* no need to check other planets for this fleet */
                  flag = 0;
                  if (glist[idx] == NULL)
                  {
                    glist[idx] = alloc (sizeof (group));
                    *glist[idx] = *g;
                    glist[idx]->next = NULL;
                  }
                  else
                  {
                    g2 = alloc (sizeof (group));
                    *g2 = *g;
                    addlist (glist[idx], g2);
                  }
                }
              }
            }
          }
        }
      flag = 0;
      prev = NULL;
      for (idx = nplanets - 1; idx >= 0; idx--)
      {
        if (glist[idx] != NULL)
        {
          P->groups = glist[idx];
          for (g = glist[idx]; g; g = g->next)
          {
            if (g->next == NULL)
            {
              g->next = prev;
              prev = glist[idx];
              break;
            }
          }
        }
      }
    }
  }
}
#else

void
sortphase (void)
{
  group *g, *g2, *newgroup = NULL;      /* For lint */
  player *P;
  planet *Pl;
  int first;
  int HasBeenSorted;
  fleetname *fl;

  first = 1;
  HasBeenSorted = 0;
  for (P = players; P; P = P->next)

#ifdef PREPROC
    /* Sorting other player's groups in the preprocessor is pointless... */
  {
    if (abs (P->lastorders) == turn + 1)
      break;                    /* We have a match */
  }
  if (P == NULL)
    P = players;                /* This shouldn't happen unless noone submitted orders */
#endif

  {
    if ((P->opts2 & SORTGROUPS))
    {
      for (Pl = planets; Pl; Pl = Pl->next)
      {
        for (g = P->groups; g; g = g->next)
        {
          if ((g->where == Pl) && (!g->fleet))
          {
            if (first)
            {
              first = 0;
              newgroup = alloc (sizeof (group));
              *newgroup = *g;
              HasBeenSorted = 1;
              newgroup->next = NULL;
            }
            else
            {
              g2 = alloc (sizeof (group));
              *g2 = *g;
              addlist (newgroup, g2);
            }
          }
        }
        for (fl = fleets; fl; fl = fl->next)
          if (fl->owner == P)
          {
            for (g = P->groups; g; g = g->next)
              if ((g->where == Pl) && (g->fleet == fl))
              {
                if (first)
                {
                  first = 0;
                  newgroup = alloc (sizeof (group));
                  *newgroup = *g;
                  HasBeenSorted = 1;
                  newgroup->next = 0;
                }
                else
                {
                  g2 = alloc (sizeof (group));
                  *g2 = *g;
                  addlist (newgroup, g2);
                }
              }
          }
      }
      if (HasBeenSorted)
      {
        HasBeenSorted = 0;
        P->groups = newgroup;
      }
      first = 1;
    }
  }
}
#endif

void
candnphase (void)
{
  tmppname *pname;
  player *P;

#if SMARTC && !(FORECAST)
  FILE *pwf, *pwf2;
  char rpl[MAXSTRLEN], tline2[MAXSTRLEN], *tline;
  char rpll[MAXPLAY][MAXSTRLEN];
  int idx, j, k, len;

  idx = 0;                      /* Shut of gcc warning about not init'd */
  pwf2 = NULL;
  memset (rpl, 0, MAXSTRLEN);
  if (tmpname)
  {                             /* Update password file */

#ifdef PASSWORDS
    for (pname = tmpname; pname; pname = pname->next)
    {
      P = nametop (players, pname->oname);
      if (P)
      {
        pwf = fopen (PASSWORDFILE, "r");
        if (pwf == NULL)
        {
          error ("Missing Races:passwords file!\n");
          exit (MISSINGPW);
        }
        for (idx = 0;; idx++)
        {
          assert (idx <= MAXPLAY);
          if (feof (pwf))
          {
            fclose (pwf);
            break;
          }
          fscanf (pwf, "%s\n", rpl);
          len = strlen (P->name);
          if (!strncmp (P->name, rpl, (unsigned) len) && (rpl[len] == ':'))
          {                     /* Player has a password */
            fclose (pwf);       /* reopen for write */
            pwf = fopen (PASSWORDFILE, "a");
            hstrncpy (tline2, pname->nname, MAXTEXT);   /* newname */
            j = (int) strlen (tline2);
            tline2[j + 1] = '\0';
            tline2[j] = ':';
            tline = &rpl[len + 1];
            strncat (tline2, tline, MAXTEXT);
            fprintf (pwf, "%s\n", tline2);
            fclose (pwf);
            break;
          }
        }
      }
    }
#endif

    pwf = fopen ("races:players", "r");
    pwf2 = fopen ("players:races", "w");
    if ((pwf == NULL) || (pwf2 == NULL))
    {
      error ("Missing races:players file!\n");
      exit (MISSINGRP);
    }
    for (idx = 0;; idx++)
    {
      assert (idx <= MAXPLAY);
      if (feof (pwf))
      {
        fclose (pwf);
        break;
      }
      fgets (rpl, MAXSTRLEN - 1, pwf);
      fprintf (pwf2, "%s", rpl);
      rpl[strlen (rpl)] = '\0';
      hstrncpy (&rpll[idx][0], rpl, MAXSTRLEN);
    }
  }
#endif

  for (pname = tmpname; pname; pname = pname->next)
  {
    P = nametop (players, pname->oname);
    if (P)
    {

#if SMARTC && !(FORECAST)
      for (j = 0; j < idx; j++)
      {
        k = (int) strlen (pname->oname);
        if ((!strncasecmp (pname->oname, &rpll[j][0], STRNCMPT k) &&
             (rpll[j][k] == ':')))
        {
          tline = strchr (&rpll[j][0], (int) ':');
          hstrncpy (tline2, pname->nname, MAXTEXT);
          hstrncpy (tline2 + strlen (tline2), tline, MAXSTRLEN);
          fprintf (pwf2, "%s\n", tline2);
          break;
        }
      }
#endif

      strcpy (P->name, pname->nname);
    }
  }

#if SMARTC  && !(FORECAST)
  if (tmpname)
  {
    fclose (pwf2);
    if (rename ("players:races", "races:players"))
    {

#ifdef OSF1                     /* Who knows where these are... */
      fprintf (stderr, "Rename of players:races failed\n");
#else
      fprintf (stderr, "Rename of players:races failed, error number %d\n", errno);
#endif

      exit (MISSINGPW);         /* This is not right. Sigh. */
    }
  }
#endif

  freelist (tmpname);
  tmpname = NULL;
}

void
go (void)
{

#ifndef FORECAST
  battle *B;
  bombing *b;

#endif
  player *P;
  group *g;

#ifdef VERBOSE
  printf ("Running turn\nHouse cleaning\n");
#endif

  turn_run = 1;

#ifndef FORECAST
  for (B = battles; B; B = B->next)
  {
    freelist (B->shots);
    freelist (B->viewers);
  }
  freelist (battles);
  battles = NULL;

  for (b = bombings; b; b = b->next)
    freelist (b->viewers);
  freelist (bombings);
  bombings = NULL;

  {
    player *P2;

    for (P = players; P;)       /* delete dead players, if needed */
    {
      P2 = P->next;
      delete_player (P, 0);
      P = P2;
    }
  }
#endif

  /* Bugfix to deal with upgrade side effects */
  for (P = players; P; P = P->next)
    for (g = P->groups; g; g = g->next)
    {
      if (g->dist == UPG)
        g->dist = 0.0;
    }
  joinphase ();

#ifndef FORECAST

#ifdef VERBOSE
  printf ("First battle phase\n");
#endif

  fightphase ();
  bombphase ();
#endif

#ifdef VERBOSE
  printf ("Routes, intercepts, movement, merging\n");
#endif

  loadphase ();
  fleetphase ();

#ifndef FORECAST
  interceptphase ();
#endif

  movephase ();
  joinphase ();

#ifndef FORECAST

#ifdef VERBOSE
  printf ("Second battle phase\n");
#endif

  fightphase ();
  bombphase ();
#endif

#ifdef VERBOSE
  printf ("Route unloading, production, merging\n");
#endif

  unloadphase ();
  producephase ();
  joinphase ();

#ifdef VERBOSE
  printf ("Sorting planets\n");
#endif

  sortplanets ();               /* GE: compile list of planets for reports */

#ifdef VERBOSE
  printf ("Sorting groups\n");
#endif

  sortphase ();                 /* sort groups, if need be */
  fleetphase ();
  candnphase ();
  turn++;

#ifdef VERBOSE
  printf ("Done with turn\n");
#endif

#ifndef PREPROC
  {
    player *P2;

    printf ("Checking for inactive players...\n");
    for (P2 = players; P2; P2 = P2->next)
    {
      if ((abs (P2->lastorders) + 1 < turn) || ((turn > 0) && P2->lastorders == 0))
      {
        if (P2->lastorders < 0)
          printf ("%s last had orders for turn %d, but is basically dead\n",
                  P2->name, abs (P2->lastorders));
        else
          printf ("%s last had orders for turn %d\n", P2->name, P2->lastorders);
      }
    }
  }
#endif
}
#endif
