static char *rcsid = "$Header: /plaid/homes/zeus/Blind-2.47/report/RCS/ships.c,v 2.47 1998/04/15 21:37:54 zeus Exp zeus $";

/*
 * $Log: ships.c,v $
 * Revision 2.47  1998/04/15 21:37:54  zeus
 * *** empty log message ***
 *
 * Revision 2.46  1997/04/18 12:25:12  zeus
 * *** empty log message ***
 *
 * Revision 2.45  1997/01/01  00:30:39  zeus
 * Revision 2.44  1995/12/31  19:45:18  zeus
 * Revision 2.43  1995/03/20  01:43:09  zeus
 *
 */

#define NOTIMEB
#include "common.h"
#include "prototypes.h"
#include "report-g.h"
#include "report.h"
#include "misc-g.h"
#include "options.h"

extern char buf[];
extern char buf2[];
extern player *players;
extern planet *planets;
extern battle *battles;
extern int vieweropts;
extern shiptype *shiptypes;
extern fleetname *fleets;

#ifdef FORECAST
extern int seenlist[];

#endif

void report_ships_rcsid (void);

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

/* Assumes that we can see *T */
int
numinclass (shiptype * T, player * P, int flag)
{
  group *g;
  int num = 0;

#ifndef PREPROC
  int exist = 0;
  planet *p;
  participant *PA, *PA2;
  battle *B;

#endif

  /* Return number seen at end of turn */
  for (g = T->owner->groups; g; g = g->next)
  {
    if (g->type == T)
    {
      if (flag)                 /* We own the class or GM cheat mode */
        num += g->ships;
      else if (canseeplanet (P, g->where, 1) && (g->dist == 0.0))
        num += g->ships;
    }
  }

#ifndef PREPROC
  for (B = battles; B; B = B->next)
  {
    /* If you can see the battle site value should be, you can
       already see what ships are left; if you lost, you can not */
    if (!canseeplanet (P, B->where, 1))
    {
      for (PA2 = B->participants; PA2; PA2 = PA2->next) /* 1/8/97 BUG FIX */
      {
        if (PA2->who == P)      /* Then we were involed in this battle */
        {
          for (PA = B->participants; PA; PA = PA->next)
          {
            if (PA->who == T->owner)
            {
              for (g = PA->groups; g; g = g->next)
              {
                if (g->type == T)
                {
                  num += g->left;
                  exist = 1;
                }
              }
            }
          }
          break;
        }
      }
    }
    /*  We own the class or GM cheat mode, and none are in one piece */
    if ((num == 0) && (exist) && (flag))
      return (SOMEEXIST);

    if (num == 0)               /* None seen in battle, or at end of turn */
      for (p = planets; p; p = p->next)
      {
        /* producing a ship there, of that type, we can see it */
        if ((p->producing == PR_SHIP) && (p->producingshiptype == T)
            && (canseeplanet (P, p, 1)) && (p->owner))
          return (SOMEEXIST);   /* return as soon as we get a hit */
      }
  }
#endif

  return (num);
}

void
printshiptype (shiptype * T, player * P, int flag)
{
  double size;
  techinfo *ti;
  int num;

  fs (T->name);
  ff (T->drive);
  fi (T->nguns);
  ff (T->guns);
  ff (T->shields);
  ff (T->cargo);
  size = typemass (T);
  if (P->opts1 & FULLTYPE)
  {
    ff (size);
    if (size > 0)
    {
      /* We either own this ship, or are in GM overseeing mode */
      if (flag)
      {                         
        ff (group_speed (P->tech, T, size));
        ff (shield_str (P->tech.shields, T->shields, size));

        num = numinclass (T, P, 1);
        /* The sanity check is mostly a bugfix for the 2.3x -> 2.4x upgrade */
        /*assert(T->numbuilt >= num); */
        fi (T->numbuilt);
        fi (numinclass (T, P, 1));
      }
      else
      {
        for (ti = P->othertechs; ti; ti = ti->next)
        {
          if (ti->whoose == T->owner)
            break;
        }
        /* We can see a ship, so there must be a tech listing */
        assert (ti != NULL);
        ff (ti->tech.drive * T->drive * DRIVEMAGIC / size);
        ff (shield_str (ti->tech.shields, T->shields, size));
        fi (0);
        fi (numinclass (T, P, 0));
      }
    }
    else
    {
      ff (0.0);
      ff (0.0);
    }
  }
}

int
canseegroup (player * P, group * g)
{
  if (g->dist)
    return 0;
  if (g->where->owner == P)
    return 1;
  return (canseeplanet (P, g->where, 1));
}

void
printgroup (player * owner, group * g, int printno, int fleetflag)
{
  static char *loadtypename[] =
  {
    "COL",
    "CAP",
    "MAT",
    "---",
  };

/* Printno:
   PG_SIMP_BATTLE = 0: Battle (no battlesum, battle)
   PG_NO_NUM = 1: Show upgradecost, planet name/num, dist (alien group)
   PG_FULL = 2: Print group #, upgradecost, planet name/num, dist (your group)
   PG_BATSUM = 3: Print num left (battle)
 */

  if ((g->fleet) && (fleetflag == 0))
    return;

  if (printno == PG_FULL)
    fi (ptonum (owner->groups, g));

  if (printno == PG_BATSUM)
    fi (g->left);

  fi (g->ships);
  fs (g->type->name);

  if (vieweropts & TECHS)
  {
    ff (g->tech.drive);
    ff (g->tech.guns);
    ff (g->tech.shields);
    ff (g->tech.cargo);
  }
  else
  {
    ff (g->tech.drive * g->type->drive);
    fi (g->type->nguns);
    ff (g->tech.guns * g->type->guns);
    ff (shield_str (g->tech.shields, g->type->shields, shipmass (g)));
    ff (cargospace (g));
  }
  if (g->type->owner == owner)
    fs (loadtypename[g->loadtype]);
  else if (g->load > 0.0)
    fs ("???");
  else
    fs ("---");
  ff (g->load);
  ff (shipmass (g));
  ff (group_speed (g->tech, g->type, shipmass (g)));
  if ((printno == PG_NO_NUM) || (printno == PG_FULL))
  {
    if (vieweropts & UPCOST)
    {
      ff (upgrade_cost (owner, g));
    }
    if (g->dist)
    {

#ifdef FORECAST
      /* Only print a planet name unless you own it in forecast mode */
      if (seenlist[ptonum (planets, g->where)])
#else
      if (canseeplanet (owner, g->where, 1))
#endif

      {
        if (vieweropts & SHOWFROM)
          fs (g->from->num);
        else
          fs (g->where->name);
      }
      else if (vieweropts & SHOWFROM)
        fs (g->from->num);
      else
        fs ("?");
      fs (g->where->num);
      ff (g->dist);
    }
    else
    {

#ifdef FORECAST
      /* Only print a planet name unless you own it in forecast mode */
      if (seenlist[ptonum (planets, g->where)])
#endif

        fs (g->where->name);

#ifdef FORECAST
      else
        fs ("?");
#endif

      fs (g->where->num);
      fs ("");
    }
  }
}

void
print_shiptypes (player * P, int flag)
{
  player *P2;
  group *g;
  shiptype *T;
  battle *B;
  viewer *V;
  participant *PA;
  planet *p;

  if (P->opts1 & FULLTYPE)
  {
    fbegin ("Your Ship Types", "xfiffffffii");
    fhead ("NDAWSCMSs#X");
  }
  else
  {
    fbegin ("Your Ship Types", "xfifff");
    fhead ("NDAWSC");
  }
  for (T = shiptypes; T; T = T->next)
    if (T->owner == P)
      printshiptype (T, P, 1);
  fend ();

  if (flag)
  {
    for (P2 = players; P2; P2 = P2->next)
      if (P2 != P)
      {
        for (T = shiptypes; T; T = T->next)
          T->flag = 0;
        for (B = battles; B; B = B->next)
        {
          for (V = B->viewers; V; V = V->next)
            if (V->who == P)
              break;
          if (V)
          {
            for (PA = B->participants; PA; PA = PA->next)
              if (PA->who == P2)
                break;
            if (PA)
              for (g = PA->groups; g; g = g->next)
                g->type->flag = 1;
          }
        }
        for (g = P2->groups; g; g = g->next)
          if (canseegroup (P, g))
            g->type->flag = 1;
        for (p = planets; p; p = p->next)
          if (p->owner == P2 && p->producing == PR_SHIP && canseeplanet (P, p, 1))
            p->producingshiptype->flag = 1;
        strcpy (buf, P2->name);
        ckunderscores (buf);
        strcat (buf, " Ship Types");
        if (P->opts1 & FULLTYPE)
        {
          fbegin (buf, "xfiffffffii");
          fhead ("NDAWSCMSs#X");
        }
        else
        {
          fbegin (buf, "xfifff");
          fhead ("NDAWSC");
        }
        for (T = shiptypes; T; T = T->next)
          if (T->flag && T->owner == P2)
            printshiptype (T, P, 0);
        fend ();
      }
  }
}

void
print_groups_at_planet (player * P, planet * p)
{
  group *g;

#ifndef FORECAST
  player *P3;

#endif

  if (P->name[0])               /* Player Name set, i.e. not GM cheat mode */
  {
    sprintf (buf, "Your groups at %s", p->name);
    if ((P->opts2 & TECHS) && (P->opts2 & UPCOST))
    {
      fbegin (buf, "iixffffxffffxxf");
      fhead ("G#TDWSCTQMSIDLR");
    }
    else if (P->opts2 & UPCOST)
    {
      fbegin (buf, "iixfifffxffffxxf");
      fhead ("G#TDAWSCTQMSIDLR");
    }
    else if (P->opts2 & TECHS)
    {
      fbegin (buf, "iixffffxfffxxf");
      fhead ("G#TDWSCTQMSDLR");
    }
    else
    {
      fbegin (buf, "iixfifffxfffxxf");
      fhead ("G#TDAWSCTQMSDLR");
    }

    for (g = P->groups; g; g = g->next)
      if (g->where == p)
        printgroup (P, g, PG_FULL, 0);
    fend ();

    print_fleets_at_planet (P, p);
  }

#ifndef FORECAST
  /* print all alien groups at the planet */

  for (P3 = players; P3; P3 = P3->next)
    /* canseeplanet call redundant, since fend() will clean up emptys */
    if ((P3 != P))
    {
      strcpy (buf2, P3->name);
      ckunderscores (buf2);
      sprintf (buf, "%s groups at ", buf2);
      strcpy (buf2, p->name);
      ckunderscores (buf2);
      strcat (buf, buf2);
      if (P->opts2 & TECHS)
      {
        fbegin (buf, "ixffffxfffxxf");
        fhead ("#TDWSCTQMSDL ");
      }
      else
      {
        fbegin (buf, "ixfifffxfffxxf");
        fhead ("#TDAWSCTQMSDL ");
      }

      {
        int foo = vieweropts;

        if (vieweropts & UPCOST)
          vieweropts = vieweropts ^ UPCOST;
        for (g = P3->groups; g; g = g->next)
        {
          if ((g->where == p) && (g->dist == 0.0) && P)
            printgroup (P3, g, PG_NO_NUM, 1);
          if ((g->where == p) && P == NULL)     /* GM Cheat mode */
            printgroup (P3, g, PG_FULL, 1);
        }
        vieweropts = foo;
      }
      fend ();
    }
#endif
}

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

  if ((P->opts2 & TECHS) && (P->opts2 & UPCOST))
  {
    fbegin ("Your Groups", "iixffffxffffxxf");
    fhead ("G#TDWSCTQMSIDLR");
  }
  else if (P->opts2 & UPCOST)
  {
    fbegin ("Your Groups", "iixfifffxffffxxf");
    fhead ("G#TDAWSCTQMSIDLR");
  }
  else if (P->opts2 & TECHS)
  {
    fbegin ("Your Groups", "iixffffxfffxxf");
    fhead ("G#TDWSCTQMSDLR");
  }
  else
  {
    fbegin ("Your Groups", "iixfifffxfffxxf");
    fhead ("G#TDAWSCTQMSDLR");
  }
  for (g = P->groups; g; g = g->next)
    printgroup (P, g, PG_FULL, 0);
  fend ();
}

void
print_fleets_at_planet (player * P, planet * p)
{
  group *g, *g2;
  fleetname *fl;
  char buf3[MAXTEXT];
  char buf4[MAXSTRLEN];
  double mass;

  for (fl = fleets; fl; fl = fl->next)
    if (P == fl->owner)
    {
      for (g = P->groups; g; g = g->next)
      {
        if (g->fleet == fl)
        {
          if (g->where != p)    /* Fleet isn't at planet, bail */
            break;
          else
          {
            strcpy (buf3, fl->name);
            ckunderscores (buf3);
            mass=fleet_mass(fl);
            sprintf (buf4, "Fleet %s (speed %.2f) (mass %.2f)", buf3, fl->fleetspeed,mass);
            if ((P->opts2 & TECHS) && (P->opts2 & UPCOST))
            {
              fbegin (buf4, "iixffffxffffxxf");
              fhead ("G#TDWSCTQMSIDLR");
            }
            else if (P->opts2 & UPCOST)
            {
              fbegin (buf4, "iixfifffxffffxxf");
              fhead ("G#TDAWSCTQMSIDLR");
            }
            else if (P->opts2 & TECHS)
            {
              fbegin (buf4, "iixffffxfffxxf");
              fhead ("G#TDWSCTQMSDLR");
            }
            else
            {
              fbegin (buf4, "iixfifffxfffxxf");
              fhead ("G#TDAWSCTQMSDLR");
            }
            for (g2 = g; g2; g2 = g2->next)
              if (g2->fleet == fl)
                printgroup (P, g2, PG_FULL, 1);
            fend ();
            break;
          }
        }
      }
    }
}

void
print_your_fleets (player * P)
{
  group *g;
  fleetname *fl;
  char buf3[MAXTEXT];
  char buf4[MAXSTRLEN];
  double mass;

  for (fl = fleets; fl; fl = fl->next)
    if (P == fl->owner)
    {
      strcpy (buf3, fl->name);
      ckunderscores (buf3);
      mass=fleet_mass(fl);
      sprintf (buf4, "Fleet %s (speed %.2f) (mass %.2f)", buf3, fl->fleetspeed,mass);
      if ((P->opts2 & TECHS) && (P->opts2 & UPCOST))
      {
        fbegin (buf4, "iixffffxffffxxf");
        fhead ("G#TDWSCTQMSIDLR");
      }
      else if (P->opts2 & UPCOST)
      {
        fbegin (buf4, "iixfifffxffffxxf");
        fhead ("G#TDAWSCTQMSIDLR");
      }
      else if (P->opts2 & TECHS)
      {
        fbegin (buf4, "iixffffxfffxxf");
        fhead ("G#TDWSCTQMSDLR");
      }
      else
      {
        fbegin (buf4, "iixfifffxfffxxf");
        fhead ("G#TDAWSCTQMSDLR");
      }
      for (g = P->groups; g; g = g->next)
        if (g->fleet == fl)
          printgroup (P, g, PG_FULL, 1);
      fend ();
    }
}

void
print_alien_groups (player * P)
{
  player *P2;
  group *g;

  for (P2 = players; P2; P2 = P2->next)
    if (P2 != P)
    {
      strcpy (buf2, P2->name);
      ckunderscores (buf2);
      sprintf (buf, "%s Groups", buf2);
      if (P->opts2 & TECHS)
      {
        fbegin (buf, "ixffffxfffxxf");
        fhead ("#TDWSCTQMSDL ");
      }
      else
      {
        fbegin (buf, "ixfifffxfffxxf");
        fhead ("#TDAWSCTQMSDL ");
      }
      {
        int oldopts = vieweropts;

        /* Upgradecost for alien groups not supported */
        if (vieweropts & UPCOST)
          vieweropts = vieweropts ^ UPCOST;
        for (g = P2->groups; g; g = g->next)
          if (canseegroup (P, g))
            printgroup (P2, g, PG_NO_NUM, 1);
        fend ();
        vieweropts = oldopts;
      }
    }
}

/* Show table of #, mass and techmass of all units at system.
   Assume that we can see the system! */

void
print_sys_mass (player *P, planet *p)
{
  player *P2;
  group *g;
  int num;
  double mass, techmass;

  fbegin ("System Group Stats","xiff");
  fhead ("N#MT");
#ifdef FORECAST
  P2=P;
#else
  for (P2= players; P2; P2=P2->next)
#endif
  {
    num=0;
    mass=techmass=0.0;
    for (g=P2->groups; g; g=g->next)
    { /* ALMOSTZERO just in case of roundoff error */
      if ((g->where==p) && (g->dist <= ALMOSTZERO ))
      {
        num+=g->ships;
        mass+=typemass(g->type)*g->ships;
        techmass+=ttechmass(g)*g->ships;
      }
    }
    if (num)
    {
      fs(P2->name);
      fi (num);
      ff(mass);ff(techmass);
    }
  }
  fend();
}

double
fleet_mass (const fleetname *fl)
{
  group *g;
  double mass;

  for (mass=0,g=fl->owner->groups;g;g=g->next)
  {
    if (g->fleet==fl)
      mass+=shipmass(g)*g->ships;
  }
  return(mass);
}
