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

/*
 * $Log: enterturn.c,v $
 * Revision 2.47  1998/04/15 21:29:39  zeus
 * *** empty log message ***
 *
 * Revision 2.46  1997/04/18 12:06:12  zeus
 * *** empty log message ***
 *
 * 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.36  1993/08/19  16:32:29  bampton
 * Revision 2.35  1993/08/14  15:46:12  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:03  bampton RCS prototype.
 *
 */

#define NOTIMEB
#define IO
#include "common.h"
#include "prototypes.h"
#include "enterturn.h"
#include "enterturn-g.h"
#include "cmds-g.h"
#include "cmds.h"
#include "misc-g.h"
#include "exit.h"
#include "options.h"

#ifdef PASSWORDS
#include <errno.h>
#endif

void enterturn_rcsid (void);

#ifdef  INTERACTIVE
#define throwstr()
#else
#define throwstr()              getstr()
#endif

extern player *players;
extern shiptype *shiptypes;
extern battle *battles;
extern char buf[MAXSTRLEN];
extern double galaxysize;
extern planet *planets;
extern int turn;

#ifdef PREPROC
int bad;
int n_order;

#include "turn-g.h"             /* For go() */
#endif

#ifdef GAMENAME
extern char gamename[MAXTEXT];

#endif

extern planetdefense *defender;
extern char err_tmp[];

int groupno;
char orders[MAXSTRLEN];


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

void
error (char msg[])
{

#ifdef PREPROC
  bad++;
  fprintf (stderr, "Mistake (%0d):'%s'\n", n_order, orders);
  fprintf (stderr, "%s", msg);
  return;
#else
  printf ("%s\n", msg);
#endif
}

/* BUG: This function is probably not written right. Check the logic
   of its usage some time. */

void
append_cmd (char *order, char *cmd)
{
  int s;


  s = strlen (order);
  assert (s + strlen (cmd) < MAXSTRLEN - 1);

  if (s != 0)
  {
    order[1 + s] = '\0';
    order[s] = ' ';
  }
  (void) strcat (order, cmd);

}

/* BUG : What what to return if not an float */
double
getf2 (void)
{

#ifndef PREPROC
REDO:
#endif

  getstr ();
  if (buf[0] && !isdigit (buf[0]) && buf[0] != '.' && buf[0] != '-')
  {
    sprintf (err_tmp, "Number expected.\n");

#ifndef PREPROC
    fprintf (stderr, "%s", err_tmp);
    goto REDO;
#else
    return 0.0;
#endif
  }
  return atof (buf);
}

void
cktech (group * g)
{
  shiptype *t;

  t = g->type;
  if (!t->drive)
    g->tech.drive = 0.0;
  if (!t->nguns)
    g->tech.guns = 0.0;
  if (!t->shields)
    g->tech.shields = 0.0;
  if (!t->cargo)
    g->tech.cargo = 0.0;
}

#ifdef PASSWORDS
int
reset_password (char *name, const char newentry[])
{
  FILE *pwf, *pwf2;
  char pwl[2 * MAXTEXT + 1];
  int j;
  int matched = 0;

  memset (pwl, 0, 2 * MAXTEXT + 1);
  pwf = fopen (PASSWORDFILE, "r");
  pwf2 = fopen ("passwords:races", "w");
  if (pwf == NULL)
  {
    error ("Password file missing!\n");
    exit (MISSINGPW);           /* Urk. No file? */
  }
  if (pwf2 == NULL)
  {
    error ("Unable to create temp password file!\n");
    exit (MISSINGPW);           /* This is wrong, but probably will never happen? */
  }
  if (name[0])
    j = strlen (name);
  else
    j = 0;                      /* Needed later */
  for (;;)
  {
    if (feof (pwf))             /* Player name not matched in file */
    {
      if ((!matched) && newentry)
        fprintf (pwf2, "%s\n", newentry);
      fclose (pwf);
      fclose (pwf2);
      if (rename ("passwords:races", PASSWORDFILE))
      {
        sprintf (err_tmp, "Rename failed, error number %d\n", errno);
        error (err_tmp);
        exit (MISSINGPW);
      }
      return (0);
    }
    /* Do the EOF check first, to deal with empty file and match on last */
    fscanf (pwf, "%s\n", pwl);

    /* Match empire. */
    if ((!strncasecmp (name, pwl, STRNCMPT strlen (name))) && (pwl[j] == ':'))
    {
      if (newentry)
        fprintf (pwf2, "%s\n", newentry);
      matched = 1;
    }
    else
    {
      /* No match, so save line */
      if (pwl[0])
        fprintf (pwf2, "%s\n", pwl);
    }
  }
  assert (0);
  return (1);
}

int
verify_password (player * P, const char *pw)
{
  FILE *pwf;
  char pwfpw[MAXTEXT], pwl[MAXSTRLEN];
  int j, k;

  memset (pwl, 0, MAXSTRLEN);
  pwf = fopen (PASSWORDFILE, "r");
  if (pwf == NULL)
  {
    error ("Password file missing!\n");
    exit (MISSINGPW);           /* Urk. No file? */
  }
  j = strlen (P->name) + 1;     /* Needed later */
  for (;;)
  {
    if (feof (pwf))             /* Player name not matched in file */
    {
      fclose (pwf);
      if (strlen (pw) == 0)
        return (0);             /* No password given, or req'd */
      error ("Player name missing from password file\n");
      return (1);
    }
    /* Do the EOF check first, to deal with empty file and match on last */
    fscanf (pwf, "%s\n", pwl);

    /* Match empire name check. */
    if ((!strncasecmp (P->name, pwl, STRNCMPT strlen (P->name))) && (pwl[j - 1] == ':'))
    {
      for (k = 0; pwl[k + j]; k++)
        pwfpw[k] = pwl[k + j];
      pwfpw[k] = '\0';
      if (strlen (pw) == strlen (pwfpw))        /* Potential match */
      {
        fclose (pwf);
        if (hstricmp (pw, pwfpw) != 0)
        {
          sprintf (err_tmp, "Password %s not matched for %s\n", pw, P->name);
          return (1);
        }
        return (0);             /* Matched */
      }
      else
      {
        fclose (pwf);
        sprintf (err_tmp, "Password %s not matched for %s\n", pw, P->name);
        return (1);
      }
    }
  }
  assert (0);                   /* Should have been given a valid player name */
  return (1);
}
#endif

#ifdef ZCMDOK
int
reset_email (char *name, const char newentry[])
{
  FILE *pwf, *pwf2;
  char pwl[MAXTEXT + 2 + MAXSTRLEN];    /* BUG: multiple long email @'s */
  int j;
  int matched = 0;

  memset (pwl, 0, 5 * MAXTEXT + 1);
  pwf = fopen ("races:players", "r");
  pwf2 = fopen ("players:races", "w");
  if (pwf == NULL)
  {
    error ("Player file missing!\n");
    exit (MISSINGRP);           /* Urk. No file? */
  }
  if (pwf2 == NULL)
  {
    error ("Unable to create temp password file!\n");
    exit (MISSINGRP);           /* This is wrong, but probably will never happen? */
  }
  if (name[0])
    j = strlen (name);
  else
    j = 0;                      /* Needed later */
  for (;;)
  {
    /* Do the EOF check first, to deal with empty file and match on last */
    fgets (pwl, MAXSTRLEN - 1, pwf);
    pwl[strlen (pwl) - 1] = '\0';

    if (feof (pwf))             /* Player name not matched in file */
    {
      if ((!matched) && newentry)
      {
        fprintf (pwf2, "%s\n", newentry);
      }
      fclose (pwf);
      fclose (pwf2);
      if (rename ("players:races", "races:players"))
      {
        sprintf (err_tmp, "Rename failed, error number %d\n", errno);
        error (err_tmp);
        exit (MISSINGRP);       /* Code here is wrong too, but close */
      }
      return (0);
    }

    /* Match empire. */
    if ((!strncasecmp (name, pwl, STRNCMPT strlen (name))) && (pwl[j] == ':'))
    {
      if (newentry)
        fprintf (pwf2, "%s\n", newentry);
      matched = 1;
    }
    else
    {
      fprintf (pwf2, "%s\n", pwl);
    }
  }
  assert (0);
  return (1);
}
#endif

player *
n2inputplayer (char *prompt)
{
  int i;
  player *p;
  char *nbuf;
  char name[MAXSTRLEN];
  int quoted;                   /* For enabling "empire name" */

#ifdef PASSWORDS
  char password[MAXSTRLEN];

#endif

  printf ("%s%c", prompt, lf);
  for (;;)
  {                             /* Keep reading lines of input until EOF */
    gets (buf);
    if (feof (stdin))
      return (NULL);

    if (buf[0])
    {
      /* Non-empty line, so see if it has magic #galaxy cookie */
      if (!strncasecmp (buf, "#galaxy", 7))
      {
        nbuf = strchr (buf, ' ');       /* Find first space */
        if (nbuf == NULL)
        {
          sprintf (err_tmp, "Null gamename- \"%s\"\n", buf);
          return (NULL);
        }
        for (; nbuf;)           /* Kill whitespace */
          if ((nbuf[0] == ' ') || (nbuf[0] == '\t'))
            nbuf++;
          else
            break;

#ifdef GAMENAME
        {
          char gname[MAXSTRLEN];
          char *j;

          /* copy the gamename, and then truncate the string at first
             space or tab, then do comparison of gamename. */
          hstrncpy (gname, nbuf, MAXSTRLEN);
          for (j = gname; j; j++)
          {
            if ((j[0] == ' ') || (j[0] == '\t'))
            {
              j[0] = '\0';
              break;
            }
          }
          if (hstricmp (gname, gamename) != 0)
          {
            sprintf (err_tmp, "Gamename mismatch- \"%s\"\n", gname);
            return (NULL);
          }
        }
#endif

        /* have found & checked "#galaxy gamename" */
        nbuf = strchr (nbuf, ' ');      /* Find 2nd wordbreak */
        if (!nbuf)
          break;                /* TEMP BUGFIX */
        nbuf++;
        for (; nbuf;)
          if ((nbuf[0] == ' ') || (nbuf[0] == '\t'))
            nbuf++;
          else
            break;

        /* Now we look for and grab the playername.... */
        if (nbuf[0] == '"')     /* "blah blah" */
        {
          nbuf++;
          quoted = 1;
        }
        else
          quoted = 0;

        for (i = 0; i < strlen (nbuf); i++)
        {
          if ((nbuf[i] != ' ') && (nbuf[i] != '\t') && (nbuf[i] != '"'))
            name[i] = nbuf[i];  /* Normal */
          else
          {
            if ((nbuf[i] == ' ') && quoted)     /* quoted name, and space */
              name[i] = '_';
            else
              break;
          }
        }
        name[i] = '\0';
        /* Clean up with quoted name */
        if (quoted)
        {
          nbuf++;               /* advance by one, to dispose of trailing " */
        }

#ifdef PASSWORDS
        nbuf += i;
        for (; nbuf;)           /* Find 3rd break's whitespace end */
          if ((nbuf[0] == ' ') || (nbuf[0] == '\t'))
            nbuf++;
          else
            break;

        /* Copy password entry */
        for (i = 0; i < strlen (nbuf); i++)
          if ((nbuf[i] != ' ') && (nbuf[0] != '\t'))
            password[i] = nbuf[i];
          else
            break;
        password[i] = '\0';
#endif

        if ((p = nametop (players, name)) != 0)
        {

#ifdef PASSWORDS
          if (verify_password (p, password) != 0)
          {

#ifdef PREPROC
            error (err_tmp);
            exit (BADPW);
#else
            fprintf (stderr, "%s", err_tmp);
            return (NULL);
#endif
          }
#endif

          return p;
        }
        sprintf (err_tmp, "Player \"%s\" not found.\n", buf);
        return (NULL);
      }
    }
  }
  return (NULL);                /* BUG PROBLEM */
}

double
shipcost (shiptype * type, planet * p)
{
  double mass;

  mass = typemass (type);
  assert (p->mat >= 0.0);       /* Stupidity check */
  if (p->mat <= 0.005)          /* Round off error check */
    return ((INDPERSHIP + 1.0 / p->resources) * mass);
  if (p->mat > typemass (type))
    return (INDPERSHIP * mass);
  else
    return (((INDPERSHIP + 1.0 / p->resources) * (mass - p->mat)) + INDPERSHIP * p->mat);
}

void
setproduction (planet * p, int t)
{
  double mass;

  if (p->producing == PR_SHIP)
  {
    mass = typemass (p->producingshiptype);
    if (mass > p->mat)
    {
      p->mat += (p->inprogress / shipcost (p->producingshiptype, p)) * mass;
    }
  }
  p->inprogress = 0.0;
  p->producing = t;
}

int
inputproduction (void)
{
  static char *productionname[] =
  {
    "cap",
    "mat",
    "ship",
    "drive",
    "weapons",
    "shields",
    "cargo",
  };
  int i;

  printf ("Production type?%c", lf);
  getstr ();
  for (i = 0; i < sizeof (productionname) / sizeof (char *); i++)

    if (!hstricmp (productionname[i], buf))
      return i;
  sprintf (err_tmp, "\"%s\" is not a production type.\n", buf);
  error (err_tmp);
  return 0;
}

group *
inputgroup (player * P)
{
  group *g;

#ifndef PREPROC
LOOP:
#endif

  printf ("Group?%c", lf);
  getstr ();
  if (!hstricmp (buf, "max"))
  {
    g = P->groups;
    if (!g)
      return 0;
    while (g->next)
      g = g->next;
    return g;
  }
  if (buf[0] && !isdigit (buf[0]))
  {
    sprintf (err_tmp, "Integer expected.\n");

#ifndef PREPROC
    goto LOOP;
#endif
  }
  groupno = atoi (buf);
  if (!groupno)
    return 0;
  g = numtop (P->groups, groupno);
  if (!g)
  {
    sprintf (err_tmp, "There is no group %d.\n", groupno);
  }
  return g;
}

int
inputcargotype (void)
{
  int i;
  static char *cargonames[] =
  {
    "col",
    "cap",
    "mat",
    "emp",
  };

  printf ("Cargo?%c", lf);
  getstr ();
  if (buf[0] == 0)
    return NOCARGO;
  buf[3] = 0;
  for (i = 0; i < sizeof (cargonames) / sizeof (char *); i++)

    if (!hstricmp (cargonames[i], buf))
      return i;
  sprintf (err_tmp, "\"%s\" is not a cargo type.\n", buf);
  return 0;
}

void
Send (group * g, planet * p)
{
  g->from = g->where;
  g->where = p;
  g->dist = dist (p, g->from);
}

void
addcol (planet * p, double x)
{
  double x2 = p->size - p->pop;

  x *= POPPERCOL;
  if (x2 > x)
    x2 = x;
  p->pop += x2;
  x -= x2;
  p->mat += x2 / POPPERCOL * MATPERCOL;
  p->col += x / POPPERCOL;
}

void
unloadgroup (group * g, player * P)
{
  double x;
  planet *p;

  x = g->load * g->ships;
  p = g->where;

#ifndef FORECAST
  /* can't unload onto size 0 systems; die nothing if try */
  /* Sigh. R COL ZeroWorld  Is legal, and will crash the forecaster! */
  /* This is rare, but can happen! */
  assert (p->size);
#endif

  switch (g->loadtype)
  {
  case CG_CAP:
    p->cap += x;
    break;
  case CG_MAT:
    p->mat += x;
    break;
  case CG_COL:
    /*
     * GE: cannot settle size 0 systems
     */
    if (p->size != 0.0)
    {
      if (p->owner == NULL)
      {
        p->owner = P;
        p->producing = PR_CAP;
      }
      if (p->owner == P)
        addcol (p, x);

      else
        p->mat += x * MATPERCOL;
    }
    break;
  default:
    assert (0);
  }
  g->load = 0.0;
  g->loadtype = CG_EMPTY;

}

void
set_defend (player * P, int status, planet * p)
{
  planetdefense *df, *df2;

  if (P)
  {
    for (df = defender; df; df = df2)
    {
      df2 = df->next;
      if ((df->planet == p) && (df->defender == P))
      {                         /* They've changed a current one */
        if (status == FLUSH)
          removelist (&defender, df);
        else
          df->dipstat = status;
        break;
      }
    }
    if (!df)
    {                           /* Or added one */
      df = alloc (sizeof (planetdefense));
      df->dipstat = status;
      df->planet = p;
      df->defender = P;
      addlist (&defender, df);
    }
  }
  else                          /* Or cleaning one up */
    for (df = defender; df; df = df2)
    {
      df2 = df->next;
      if (df->planet == p)
        removelist (&defender, df);
    }
}

void
enterturn (int turnrun)
{
  player *P;


#ifdef PREPROC
  P = n2inputplayer ("");
  n_order = 0;
  bad = 0;
#else
  P = n2inputplayer ("Player?");
#endif

  if (P == NULL)
  {

#ifdef PREPROC
    error (err_tmp);
#endif

    return;
  }

#ifdef PREPROC

#ifdef FORECAST
  build_seen_list (P);
#endif

#endif

#ifndef PREPROC
  if (abs (P->lastorders) > turn)
  {
    sprintf (err_tmp, "Multiple orders detected for %s!\n", P->name);
    error (err_tmp);
    exit (DUPORDERS);
  }
#endif

  if (P->lastorders < 0)
    P->lastorders = -(turn + 1);
  else
    P->lastorders = turn + 1;

  for (;;)
  {

    orders[0] = '\0';

  LOOP:

#ifdef PREPROC
    /* Do this here so we count blank lines and such. */
    n_order++;
    printf ("%s:%d>\n", P->name, n_order);
#else
    printf ("%s>%c", P->name, lf);
    fflush (stdout);
    /* Ignoring blank lines here is OK. */
#endif

    gets (buf);
    if (feof (stdin))
    {
      error ("Missing #end, assuming that it is there\n");
      strcpy (buf, "#end");
    }
    append_cmd (orders, buf);
    if (!buf[0])
      goto LOOP;                /* Blank line */
    if ((strlen (buf) == 1) && (buf[0] == ' ' || buf[0] == '\t'))
      goto LOOP;                /* Space/TAB */

#ifdef PREPROC
    assert (bad < TOOMANYBAD + 1);      /* Sanity check */
    if (bad == TOOMANYBAD)
    {
      bad--;
      error ("Too many bad commands, giving up on remaining orders\n");
      strcpy (buf, "#end");
    }
#endif

    switch (tolower (buf[0]))
    {
    case 'a':
      a_cmd (buf, P);
      break;
    case 'b':
      b_cmd (buf, P);
      break;
    case 'c':
      c_cmd (buf, P);
      break;
    case 'd':
      d_cmd (buf, P);
      break;
    case 'e':
      e_cmd (buf, P);
      break;
    case 'f':
      f_cmd (buf, P);
      break;
    case 'g':
      g_cmd (buf, P);
      break;
    case 'h':
      h_cmd (buf, P);
      break;
    case 'i':
      i_cmd (buf, P);
      break;
    case 'j':
      j_cmd (buf, P);
      break;

#ifdef KCMD
    case 'k':
      k_cmd (buf, P);
      break;
#endif

    case 'l':
      l_cmd (buf, P);
      break;
    case 'm':
      m_cmd (buf, P);
      break;
    case 'n':
      n_cmd (buf, P);
      break;
    case 'o':
      o_cmd (buf, P);
      break;
    case 'p':
      p_cmd (buf, P);
      break;
    case 'r':
      r_cmd (buf, P);
      break;
    case 's':
      s_cmd (buf, P);
      break;
    case 't':
      t_cmd (buf, P);
      break;
    case 'u':
      u_cmd (buf, P);
      break;
    case 'w':
      w_cmd (buf, P);
      break;
    case 'x':
      x_cmd (buf, P);
      break;

#ifdef PASSWORDS
    case 'y':
      y_cmd (buf, P);
      break;
#endif

#ifdef ZCMDOK
    case 'z':
      z_cmd (buf, P);
      break;
#endif

    case ';':
      break;
    case '#':
      if (!strncasecmp (buf, "#end", 4))
      {

#ifdef FORECAST
        if ((P->opts2 & FCAST) && (turnrun == RUN))
        {
          while (abs (P->lastorders) > turn)
            go ();
          forecast_report (P);
        }
#endif

        return;
      }
      break;

    case ' ':
    case '\t':

#ifdef PREPROC                  /* Flag, in case they do <space>order */
      sprintf (err_tmp,
            "Warning! Space caused this command to be ignored '%s'\n", buf);
      error (err_tmp);
#endif

      break;

    default:

#ifdef PREPROC
      sprintf (err_tmp, "Huh? '%s'\n", buf);
      error (err_tmp);
#else
      printf ("\"%s\" is not a valid command.\n", buf);
      printf ("Available commands:\n");
      printf ("\n");
      printf ("A = Declare Peace\n");
      printf ("B = Break Up Group\n");
      printf ("C = Change Player Name\n");
      printf ("D = Design Ship Type\n");
      printf ("E = Erase Ship Type\n");
      printf ("F = Full system request\n");
      printf ("G = Upgrade\n");
      printf ("H = Declare Defensive\n");
      printf ("I = Intercept\n");
      printf ("J = Join\n");

#ifdef KCMD
      printf ("K = Planet protection\n");
#endif

      printf ("L = Load Cargo\n");
      printf ("M = Define Map Area\n");
      printf ("N = Name System\n");
      printf ("P = Set System Production\n");
      printf ("Q = Quit\n");
      printf ("R = Set Route\n");
      printf ("S = Send Group\n");
      printf ("T = Name Ship Type\n");
      printf ("U = Unload Cargo\n");
      printf ("W = Declare War\n");
      printf ("X = Scrap\n");

#ifdef PASSWORDS
      printf ("Y = Reset Password\n");
#endif

#ifdef ZCMDOK
      printf ("Z = Change Email\n");
#endif

#endif
    }
  }
}
