/*
** makestreet.c  Copyright 1991 Kent Paul Dolan,
**               Mountain View, CA, USA 94039-0755
**
** Written to satisfy an inquiry on USENet's rec.games.programmer newsgroup.
** May be freely used or modified in any non-commercial work.  Copyrighted
** only to prevent patenting by someone else.
*/

#include <stdio.h>
#include "townmaze.h"
#include "townproto.h"

#ifdef __STDC__
int makestreet(int chosencell,int streetid,int streetpoints)
#else
int makestreet(chosencell,streetid,streetpoints)
  int chosencell,streetid, streetpoints;
#endif
{

  int choseni, chosenj;
  int nhbrid, nextnhbrid, thirdnhbrid;
  int streetwalk, highstreetnum, lowstreetnum;
  int canstraighten;

/*
** Check that a street isn't going in next to an unused cell; if it is,
** mark it dead, instead if it's live; in any case, refuse to do it.
*/

  for (nhbrid = 0; nhbrid < 4; nhbrid++)
  {
    if (nhbrexists(chosencell,nhbrid))
      if (statlist[nhbris(chosencell,nhbrid)].status == UNUSED)
      {
        if (statlist[chosencell].status == LIVE)
          movefromto(&live,&livect,&dead,&deadct,DEAD,chosencell);
        return(1==0);
      }
  }
   
/*
** Check for and abide by straightness control
*/

   if ((mazestraightness > 0) && (streetpoints == -1))
     if ((RANDOM()%1000) < mazestraightness)
     {
       canstraighten = (1==0);
       for (nhbrid = 0; nhbrid < 4; nhbrid++)
         if (nhbrexists(chosencell,nhbrid))
           if (statlist[nhbris(chosencell,nhbrid)].streetdir ==
               ((nhbrid+2)%4))
             canstraighten = (1==1);
       if (!canstraighten) return(1==0);
     }
/*
** Update the chosen cell in the status list
*/
  switch (statlist[chosencell].status)
  {
  case UNUSED:
  case STREET:
    fprintf(stderr,"error picking street; bad cell status %d\n",
      statlist[chosencell].status);
    freespace();
    exit(1);
    break;

  case LIVE:
/*  fprintf(stderr,"moving cell %d from live to street\n",chosencell); */
    movefromto(&live,&livect,&street,&streetct,STREET,chosencell);
    break;

  case DEAD:
/*  fprintf(stderr,"moving cell %d from dead to street\n",chosencell); */
    movefromto(&dead,&deadct,&street,&streetct,STREET,chosencell);
    break;

  case ISOLATED:
/*  fprintf(stderr,"moving cell %d from isolated to street\n",chosencell);*/
    movefromto(&isolated,&isolatedct,&street,&streetct,STREET,chosencell);
    break;

  default:
    fprintf(stderr,"unexpected chosencell status in makegates %d\n",
      statlist[chosencell].status);
  }

/*
** Give the street the required streetid, either new or continuing an
** existing street.
*/

  statlist[chosencell].streetnum = streetid;

/*
** Update the chosen cell on the map.
*/

  choseni = chosencell / (mazewidth/2);
  chosenj = chosencell % (mazewidth/2);

  choseni = 2 * choseni + 1;
  chosenj = 2 * chosenj + 1;

  cmaze[choseni - 1][chosenj] = HDOOR;
  cmaze[choseni][chosenj + 1] = VDOOR;
  cmaze[choseni + 1][chosenj] = HDOOR;
  cmaze[choseni][chosenj - 1] = VDOOR;

/*
** Update the neighbors of the new street cell;
*/

  for (nhbrid = 0; nhbrid < 4; nhbrid++)
  {
    if (nhbrexists(chosencell,nhbrid))
    switch (statlist[nhbris(chosencell,nhbrid)].status)
    {
    case UNUSED:
      fprintf(stderr,
              "logic error; tried to put a street beside an unused cell\n");
      showdebugmaze();
      freespace();
      exit(1);
      break;
    case STREET:
      switch (nhbrid) /* change the door to a passage, adopt a continuing */
      {               /* direction from a neighbor street */
      case 0:
        cmaze[choseni - 1][chosenj] = BLANK;
        if (statlist[nhbris(chosencell,nhbrid)].streetdir == 2)
          statlist[chosencell].streetdir = 2;
        break;
      case 1:
        cmaze[choseni][chosenj + 1] = BLANK;
        if (statlist[nhbris(chosencell,nhbrid)].streetdir == 3)
          statlist[chosencell].streetdir = 3;
        break;
      case 2:
        cmaze[choseni + 1][chosenj] = BLANK;
        if (statlist[nhbris(chosencell,nhbrid)].streetdir == 0)
          statlist[chosencell].streetdir = 0;
        break;
      case 3:
        cmaze[choseni][chosenj - 1] = BLANK;
        if (statlist[nhbris(chosencell,nhbrid)].streetdir == 1)
          statlist[chosencell].streetdir = 1;
        break;
      default:
        fprintf(stderr,"bad nhbrid in nhbr update street switch case\n");
        /* The above should be impossible; nhbrexists and nhbris already */
        /* both checked for this problem */
        showdebugmaze();
        freespace();
        exit(1);
      }

      if (statlist[chosencell].streetnum !=
          statlist[nhbris(chosencell,nhbrid)].streetnum)
      {

/*
** Two different streets have met; merge their streetids and decrement the
** streetcount.
*/

        lowstreetnum =
          ( ( statlist[chosencell].streetnum >
              statlist[nhbris(chosencell,nhbrid)].streetnum )
            ? statlist[nhbris(chosencell,nhbrid)].streetnum 
            : statlist[chosencell].streetnum
          );
        highstreetnum =
          ( ( statlist[chosencell].streetnum <
              statlist[nhbris(chosencell,nhbrid)].streetnum )
            ? statlist[nhbris(chosencell,nhbrid)].streetnum 
            : statlist[chosencell].streetnum
          );

        streetwalk = street;
        while (streetwalk != NOPOINTER)
        {
          if (statlist[streetwalk].streetnum == highstreetnum)
            statlist[streetwalk].streetnum = lowstreetnum;
          streetwalk = statlist[streetwalk].next;
        }
        streetnumct--;
      }
      break;
    case DEAD: /* do nothing; that's why it's called dead */
      break;
    case LIVE:
      movefromto(&live,&livect,&dead,&deadct,DEAD,nhbris(chosencell,nhbrid));
      for (nextnhbrid = 0; nextnhbrid < 4; nextnhbrid++)
        if (nhbrexists(nhbris(chosencell,nhbrid),nextnhbrid))
          if (statlist[nhbris(nhbris(chosencell,nhbrid),nextnhbrid)].status
              == ISOLATED)
          {
            movefromto(&dead,&deadct,&live,&livect,LIVE,
                       nhbris(chosencell,nhbrid));
            break;
          }
      break;
    case ISOLATED:
      movefromto(&isolated,&isolatedct,&dead,&deadct,DEAD,
                 nhbris(chosencell,nhbrid));
      statlist[nhbris(chosencell,nhbrid)].status = DEAD;
/*
** Only let an isolated cell become live if it is interior; stops
** streets from running along the city wall, creating lots of gates.
** Don't make it live if it is next to an unused cell, either, since
** it can never become a street cell.
*/
      if (   interiorcell(nhbris(chosencell,nhbrid))
          && (statlist[nhbris(nhbris(chosencell,nhbrid),0)].status != UNUSED)
          && (statlist[nhbris(nhbris(chosencell,nhbrid),1)].status != UNUSED)
          && (statlist[nhbris(nhbris(chosencell,nhbrid),2)].status != UNUSED)
          && (statlist[nhbris(nhbris(chosencell,nhbrid),3)].status != UNUSED)
         )
        for (nextnhbrid = 0; nextnhbrid < 4; nextnhbrid++)
          if (nhbrexists(nhbris(chosencell,nhbrid),nextnhbrid))
            if (statlist[nhbris(nhbris(chosencell,nhbrid),nextnhbrid)].status
                == ISOLATED)
            {
              movefromto(&dead,&deadct,&live,&livect,LIVE,
                         nhbris(chosencell,nhbrid));
              break;
            }
/*
** When an isolated cell stops being so, neighbors may stop being live
** that were depending on it for that status; we're not done!
*/
      for (nextnhbrid = 0; nextnhbrid < 4; nextnhbrid++)
        if (nhbrexists(nhbris(chosencell,nhbrid),nextnhbrid))
          if (statlist[nhbris(nhbris(chosencell,nhbrid),nextnhbrid)].status
              == LIVE)
          {
            movefromto(&live,&livect,&dead,&deadct,DEAD,
                       nhbris(nhbris(chosencell,nhbrid),nextnhbrid));
            for (thirdnhbrid =0; thirdnhbrid <4; thirdnhbrid++)
            {
              if (nhbrexists(nhbris(nhbris(chosencell,
                                    nhbrid),
                             nextnhbrid),
                  thirdnhbrid))
                if (statlist[nhbris(nhbris(nhbris(chosencell,
                                           nhbrid),
                                    nextnhbrid),
                             thirdnhbrid)].status
                    == ISOLATED)
                {
                  movefromto(&dead,&deadct,&live,&livect,LIVE,
                             nhbris(nhbris(chosencell,nhbrid),nextnhbrid));
                  break;
                }
            }
          }
      break;
    default:
      fprintf(stderr,"bad statlist[%d].status entry %d\n",
              nhbris(chosencell,nhbrid),
              statlist[nhbris(chosencell,nhbrid)].status);
      showdebugmaze();
      freespace();
      exit(1);
    }
  }
  if (statlist[chosencell].streetdir == -1)
     if (streetpoints != -1)
       statlist[chosencell].streetdir = streetpoints;
     else
     {
       for (nhbrid = 0; nhbrid < 4; nhbrid++)
       {
         if (nhbrexists(chosencell,nhbrid))
           if (statlist[nhbris(chosencell,nhbrid)].status == STREET)
           {
             statlist[chosencell].streetdir = ((nhbrid +2)%4);
             break;
           }
       }
     }
/*  showdebugmaze(); */
  return(1==1);
}
