/*----------------------------------------------------------------------------*
 | This file is part of DEU (Doom Editing Utilities), created by the DEU team:|
 | Raphael Quinet, Brendon Wyber, Ted Vessenes and others.  See README.1ST or |
 | the "about" dialog box for full credits.                                   |
 |                                                                            |
 | DEU is an open project: if you think that you can contribute, please join  |
 | the DEU team.  You will be credited for any code (or ideas) included in    |
 | the next version of the program.                                           |
 |                                                                            |
 | If you want to make any modifications and re-distribute them on your own,  |
 | you must follow the conditions of the DEU license.  Read the file LICENSE  |
 | in this directory or README.1ST in the top directory.  If do not have a    |
 | copy of these files, you can request them from any member of the DEU team, |
 | or by mail: Raphael Quinet, Rue des Martyrs 9, B-4550 Nandrin (Belgium).   |
 |                                                                            |
 | This program comes with absolutely no warranty.  Use it at your own risks! |
 *----------------------------------------------------------------------------*

 M_ALIGN.C - Align textures

 Created on Feb 23,1995 by Mark K. Mathews

*/


/* the includes */
#include "deu.h"
#include <math.h>
#include "d_misc.h"
#include "d_config.h"
#include "g_gfx.h" /* color names */
#include "i_dialog.h"
#include "i_menus.h"
#include "i_textur.h"
#include "w_lindef.h"
#include "m_align.h"


static Int16 GetTextureRefHeight(LevelPtr level, Int16 linedef, Int16 sidedef)
{
  Int16 othersector, otherside, type_number;
  Int8 *type;

  if (level->linedefs[linedef].sidedef1 == sidedef)
    {
      otherside = level->linedefs[linedef].sidedef2;
    }
  if (level->linedefs[linedef].sidedef2 == sidedef)
    {
      otherside = level->linedefs[linedef].sidedef1;
    }
  /* get type number of Linedef of otherside */
  type_number = level->linedefs[linedef].type;

  /* get the Sector number */
  othersector = level->sidedefs[sidedef].sector;

  /* if the upper texture is displayed, then the reference is taken from the other Sector */
  if (otherside >= 0)
    {
      linedef = level->sidedefs[otherside].sector;
      if (linedef > 0)
        {
          if (level->sectors[linedef].ceilh < level->sectors[othersector].ceilh && level->sectors[linedef].ceilh > level->sectors[othersector].floorh)
            othersector = linedef;
          else
            /* case 2:  wall as lower texture only
                        return floor height
            */
            if (level->sectors[linedef].floorh > level->sectors[othersector].floorh)
              return level->sectors[linedef].floorh;
        }
    }

  /*
     Check Linedef type
      case 1: door
     floor height = ceiling height
  */
  type = GetLineDefTypeName(type_number);
  if (strstr(type, "Door") != NULL || strstr(type, "door") != NULL)
    return 0;

  /* return the altitude of the ceiling */
  if (othersector >= 0)
    return level->sectors[othersector].ceilh; /* textures are drawn from the ceiling down */
  else
    return 0; /* yuck! */
}


/*
   get the absolute WALL height from which the textures are drawn

   sidedef     - this side of linedef
   otherside   - other side of linedef
   othersector - other sector of otherside

*/

static Int16 GetTextureWallHeight(LevelPtr level, Int16 linedef, Int16 sidedef)
{
  Int16 thissector, otherside, type_number;
  Int8 *type;

  if (level->linedefs[linedef].sidedef1 == sidedef)
    {
      otherside = level->linedefs[linedef].sidedef2;
    }
  if (level->linedefs[linedef].sidedef2 == sidedef)
    {
      otherside = level->linedefs[linedef].sidedef1;
    }
  /* get type number of Linedef */
  type_number = level->linedefs[linedef].type;

  /* get the Sector number of otherside */
  thissector = level->sidedefs[sidedef].sector;

  if (otherside >= 0)
    {
      linedef = level->sidedefs[otherside].sector;
      if (linedef > 0)
        return level->sectors[linedef].floorh - level->sectors[thissector].floorh;
    }
  /*
     Check Linedef type

      case 1: door
      floor height = ceiling height
  */

  type = GetLineDefTypeName(type_number);
  if (strstr(type, "Door") != NULL || strstr(type, "door") != NULL)
    return 0;

  return 0; /* yuck! */
}

/*

  Align all highlighted textures in the Y-axis.

  static void AlignTexturesY(LevelPtr level, SelPtr *ldlist, Bool type_sd,
                             Int8 MaxTexture, Bool type_off,
                             Bool align_bottom, Bool unpeg_flag)

  LevelPtr level    WAD structure
  SelPtr *ldlist    List of linedefs selected
  Bool type_sd      align FALSE-SideDef 1 or TRUE-SideDef2
  Int8 MaxTexture   0,3 - Find largest texture
                      1 - Upper is largest
                      2 - Lower is largest
  Bool type_off     If TRUE we have an initial offset to use
  Bool align_bottom If TRUE align lower texture to bottom
  Bool unpeg_flag   If TRUE set unpeg flag of lower and upper texture

*/

static void AlignTexturesY(LevelPtr level, SelPtr *ldlist, Bool type_sd,
                           Int8 MaxTexture, Bool type_off,
                           Bool align_bottom, Bool unpeg_flag)
{
  char  uppertexname[9] = "";   /* UPPER texture name used in the highlited objects */
  char  lowertexname[9] = "";   /* LOWER texture name used in the highlited objects */
  char  normaltexname[9] = "";  /* NORMAL texture name used in the highlited objects */
  char  errormessage[80] = "";  /* area to hold the error messages produced */
  Int16 h;
  Int16 refh;
  Int16 texheight, dummy;
  Int16 ldef;                   /* linedef number */
  Int16 ldefnext;
  Int16 sdcur;                  /* current SideDef in *ldlist */
  Int16 sdnext = 0;             /* next    SideDef in *ldlist */
  Int16 side1, side2;           /* sidedefs */
  Int16 useroffset = 0;         /* user input offset for first input */
  Bool  ldef_dir = FALSE;       /* FALSE - MINUS direction, TRUE - PLUS direction */
  Bool  ldefnext_dir = FALSE;
  Bool  first_time = FALSE;     /* first time flag then set to TRUE */
  Bool  secret_flag;            /* set if linedef is secret */
  Bool  end_of_group = 0;


  if (*ldlist == NULL)
    return;

NEXT_LINE:

  /* get current linedef number */
  ldef = (*ldlist)->objnum;

  /* Is there more than 1 LineDef selected? */
  if ((*ldlist)->next == NULL)
    {
      Beep();
      strcpy(errormessage, "More than 1 LineDef must be selected in sequence");
      Notify(-1, -1, errormessage, NULL);
      return;
    }

  /* Does sidedef exist? */
  if ((type_sd == FALSE && level->linedefs[ldef].sidedef1 == -1)
      || (type_sd == TRUE && level->linedefs[ldef].sidedef2 == -1))
    {
      Beep();
      if (type_sd == FALSE)
        sprintf(errormessage, "No sidedef 1 for LineDef #%d. Do you want to try Sidedef 2?", ldef);
      else
        sprintf(errormessage, "No sidedef 2 for LineDef #%d. Do you want to try Sidedef 1?", ldef);
      if (!Confirm(-1, -1, errormessage, NULL))
        return;
      /* toggle type_sd */
      type_sd = !type_sd;
      goto NEXT_LINE;
    }

  /* get next linedef number */
  ldefnext = (*ldlist)->next->objnum;

  if(type_sd == FALSE)
    sdcur = level->linedefs[ldef].sidedef1;
  else
    if (type_sd == TRUE)
      sdcur = level->linedefs[ldef].sidedef2;

  if (sdcur == -1)
    {
      Beep();
      sprintf(errormessage, "Sidedef = -1 for LineDef #%d.", ldef);
      Notify(-1, -1, errormessage, NULL);
      return;
    }
  if (end_of_group == FALSE)
    if (align_bottom == TRUE)
      refh = GetTextureWallHeight(level, ldef, sdcur);
    else
      refh = GetTextureRefHeight(level, ldef, sdcur);


  /* get initial offset to use (if required) */
  if (type_off == 1)
    {
      useroffset = InputIntegerValue(-1, -1,
                                     "Enter initial ceiling height between -16384 and 16383",
                                     -16384, 16383, 0);

      /* user pressed ESC key */
      if (useroffset == -32767)
        return;
    }
  end_of_group = FALSE;

  while (*ldlist != NULL)  /* main processing loop */
    {
      /* get texture names of current SideDef */
      strncpy(uppertexname, level->sidedefs[sdcur].tex1, 8); /* upper texture */
      strncpy(lowertexname, level->sidedefs[sdcur].tex2, 8); /* lower texture */
      strncpy(normaltexname, level->sidedefs[sdcur].tex3, 8); /* normal texture */

      /* Does a texture exist for current SideDef? */
      if ((uppertexname[0] == '-' && lowertexname[0] == '-' && normaltexname[0] == '-'))
        {
          Beep();
          if (type_sd == FALSE)
            sprintf(errormessage, "No texture for sidedef 1 - #%d. Do you want to try Sidedef 2?", sdcur);
          else
            sprintf(errormessage, "No texture for sidedef 2 - #%d. Do you want to try Sidedef 1?", sdcur);
          if (!Confirm(-1, -1, errormessage, NULL))
            return;
          /* toggle type_sd */
          type_sd = !type_sd;
          goto NEXT_LINE;
        }

      texheight = 0;
      switch (MaxTexture)
        {
          case 0:
          case 3:
            {
              Int16 upper = 0, lower = 0;

              /* find largest texture in height */
              if (normaltexname[0] != '-')
                GetWallTextureSize(&dummy, &texheight, normaltexname);
              if (uppertexname[0] != '-')
                GetWallTextureSize(&dummy, &upper, uppertexname);
              if (lowertexname[0] != '-')
                GetWallTextureSize(&dummy, &lower, lowertexname);
              if (upper > texheight)
                texheight = upper;
              if (lower > texheight)
                texheight = lower;
            }
            break;
          case 1:       /* use Upper texture as largest */
            if (uppertexname[0] != '-')
              GetWallTextureSize(&dummy, &texheight, uppertexname);
            else
              {
                Beep();
                sprintf(errormessage, "No UPPER texture for sidedef #%d.", sdcur);
                Notify(-1, -1, errormessage, NULL);
                return;
              }
            break;
          case 2:      /* use Lower texture as largest */
            if (lowertexname[0] != '-')
              {
                GetWallTextureSize(&dummy, &texheight, lowertexname);
              }
            else
              {
                Beep();
                sprintf(errormessage, "No LOWER texture for sidedef #%d.", sdcur);
                Notify(-1, -1, errormessage, NULL);
                return;
              }
            break;
          }

      /* set upper and lower texture unpegged flag */
      /* make sure it is NOT a secret door */
      if (unpeg_flag == TRUE && !(level->linedefs[ldef].flags & 0x20))
        {
          /* set upper texture unpegged*/
          if (uppertexname[0] != '-')
            level->linedefs[ldef].flags |= 0x08;
          /* set lower texture unpegged */
          if (lowertexname[0] != '-')
            level->linedefs[ldef].flags |= 0x10;
        }

      if ((*ldlist)->next == NULL) /* end of list */
        goto END_OF_LIST;

      /* get next sidedefs from next linedef */
      /* get next linedef number */
      ldefnext = (*ldlist)->next->objnum;
      /* get sidedef numbers from next linedef */
      side1 = level->linedefs[ldefnext].sidedef1;
      side2 = level->linedefs[ldefnext].sidedef2;

      /* determine direction of ldef and ldefnext */

      /* -----> -----> */
      if (level->linedefs[ldef].end == level->linedefs[ldefnext].start)
        {
          ldef_dir = TRUE;             /* FALSE - MINUS direction, TRUE - PLUS direction */
          ldefnext_dir = TRUE;
        }
      else
        /* -----> <----- */
        if (level->linedefs[ldef].end == level->linedefs[ldefnext].end)
          {
            ldef_dir = TRUE;          /* FALSE - MINUS direction, TRUE - PLUS direction */
            ldefnext_dir = FALSE;
          }
        else
          /* <----- -----> */
          if (level->linedefs[ldef].start == level->linedefs[ldefnext].start)
            {
              ldef_dir = FALSE;       /* FALSE - MINUS direction, TRUE - PLUS direction */
              ldefnext_dir = TRUE;
            }
          else
            /* <----- <----- */
            if (level->linedefs[ldef].start == level->linedefs[ldefnext].end)
              {
                ldef_dir = FALSE;    /* FALSE - MINUS direction, TRUE - PLUS direction */
                ldefnext_dir = FALSE;
              }
            else
              {
                if ((*ldlist)->next != NULL) /* end of previous group */
                  {
                    /* check secret linedef */
                    secret_flag = FALSE;
                    if ((level->linedefs[ldef].flags & 0x20))
                      secret_flag = TRUE;

                    /* set upper and lower  texture unpegged flag */
                    /* make sure its its NOT a secret door */
                    if (unpeg_flag == TRUE && !secret_flag)
                      {
                        /*set upper texture unpegged*/
                        if (uppertexname[0] != '-')
                          level->linedefs[ldef].flags |= 0x08;
                        /* set lower texture unpegged */
                        if (lowertexname[0] != '-')
                          level->linedefs[ldef].flags |= 0x10;
                      }
                    if (first_time == FALSE)
                      if (type_off == FALSE)  /* do we have an initial offset ? */
                        refh = useroffset;

                    first_time = TRUE;
                    /* make sure its its NOT a secret door */
                    if (unpeg_flag == FALSE && !secret_flag)
                      {
                        h = GetTextureRefHeight(level, ldef, sdcur);
                        if (align_bottom == TRUE)
                          level->sidedefs[sdcur].yoff = texheight - (refh % texheight);
                        else
                          level->sidedefs[sdcur].yoff = (refh - h) % texheight;
                      }
                    sdcur = sdnext;
                    ldef = ldefnext;
                  }

                UnSelectObject(ldlist, (*ldlist)->objnum);

                if (type_off == TRUE)
                  {
                    refh = useroffset;
                    type_off = FALSE; /* don't prompt for initial height */
                    end_of_group=TRUE;
                  }
                if (!Config.expert)
                  {
                    Beep();
                    sprintf(errormessage, "Starting next group with Linedef #%d.", (*ldlist)->objnum);
                    LogMessage(errormessage);
                    LogMessage("\n");
                    Notify(-1, -1, errormessage, NULL);
                  }
                goto NEXT_LINE;
              }

      if (type_sd == FALSE)
        {
          if (ldef_dir == TRUE)   /* -----> */
            {                  /*   |    */
              if (ldefnext_dir == TRUE) /* -----> */
                {                     /*   |    */
                  sdnext = side1;
                  type_sd = FALSE;
                }                  /*    |   */
              else               /* <----- */
                {
                  sdnext = side2;
                  type_sd = TRUE;
                }
            }              /*    |   */
          else           /* <----- */
            {
              if (ldefnext_dir == TRUE)  /* -----> */
                {                      /*   |    */
                  sdnext = side2;
                  type_sd = TRUE;
                }                   /*    |   */
              else                /* <----- */
                {
                  sdnext = side1;
                  type_sd = FALSE;
                }
            }
        }
      else
        if (type_sd == TRUE)
          {
            if (ldef_dir == TRUE) /* -----> */
              {                 /*   |    */
                if (ldefnext_dir == TRUE) /* -----> */
                  {                     /*   |    */
                    sdnext = side2;
                    type_sd = TRUE;
                  }                  /*    |   */
                else               /* <----- */
                  {
                    sdnext = side1;
                    type_sd = FALSE;
                  }
              }              /*    |   */
            else           /* <----- */
              {
                if (ldefnext_dir == TRUE)  /* -----> */
                  {                      /*   |    */
                    sdnext = side1;
                    type_sd = FALSE;
                  }                   /*    |   */
                else                /* <----- */
                  {
                    sdnext = side2;
                    type_sd = TRUE;
                  }
              }
          }
      if (sdnext == -1)
        {
          Beep();
          sprintf(errormessage, "Sidedef = -1 for LineDef #%d.", ldef);
          Notify(-1, -1, errormessage, NULL);
          return;
        }


END_OF_LIST:

      /* check secret linedef */
      secret_flag = FALSE;
      if ((level->linedefs[ldef].flags & 0x20))
        secret_flag = TRUE;

      /* set upper and lower  texture unpegged flag */
      /* make sure its its NOT a secret door */
      if (unpeg_flag == TRUE && !secret_flag)
        {
          /*set upper texture unpegged*/
          if (uppertexname[0] != '-')
            level->linedefs[ldef].flags |= 0x08;
          /* set lower texture unpegged */
          if (lowertexname[0] != '-')
            level->linedefs[ldef].flags |= 0x10;
        }

      if (first_time == FALSE)
        if (type_off == TRUE)  /* do we have an initial offset ? */
          refh = useroffset;

      first_time = TRUE;
      /* make sure its its NOT a secret door */
      if (unpeg_flag == FALSE && !secret_flag)
        {
          h = GetTextureRefHeight(level, ldef, sdcur);
          if (align_bottom == TRUE)
            level->sidedefs[sdcur].yoff = texheight - (refh % texheight);
          else
            level->sidedefs[sdcur].yoff = (refh - h) % texheight;
        }
      UnSelectObject(ldlist, (*ldlist)->objnum);
      sdcur = sdnext;
      ldef = ldefnext;
    }
  level->made_changes = TRUE;
}


/*

  Align all highlighted textures in the X-axis.

  static void AlignTexturesX(LevelPtr level, SelPtr *ldlist, Bool type_sd,
                             Int8 MaxTexture, Bool type_tex,
                             Bool type_off)

  LevelPtr level    WAD structure
  SelPtr *ldlist    List of linedefs selected
  Bool type_sd      align FALSE-SideDef 1 or TRUE-SideDef2
  Int8 MaxTexture   0,3 - Find largest texture
                      1 - Upper is largest
                      2 - Lower is largest
  Bool type_tex     If TRUE check for same textures
  Bool type_off     If TRUE we have an initial offset to use

*/

static void AlignTexturesX(LevelPtr level, SelPtr *ldlist, Bool type_sd,
                           Int8 MaxTexture, Bool type_tex, Bool type_off)
{
  char  uppertexname[9] = "";   /* UPPER texture name used in the highlited objects */
  char  lowertexname[9] = "";   /* LOWER texture name used in the highlited objects */
  char  normaltexname[9] = "";  /* NORMAL texture name used in the highlited objects */
  char  texname[9] = "";
  char  errormessage[80] = "";  /* area to hold the error messages produced */
  Int16 ldef;                   /* linedef number */
  Int16 ldefnext;
  Int16 sdcur;                  /* current SideDef in *ldlist */
  Int16 sdnext;                 /* next    SideDef in *ldlist */
  Int16 side1, side2;           /* sidedefs */
  Int16 vert1 = -1, vert2 = -1; /* vertex 1 and 2 for the linedef under scrutiny */
  Int16 xoffset = 0;            /* xoffset accumulator */
  Int16 useroffset = 0;         /* user input offset for first input */
  Int16 texlength = 0;          /* the length of texture to format to */
  Int16 length;                 /* length of linedef under scrutiny */
  Int16 dummy;              /* holds useless data */
  Bool  ldef_dir = FALSE;           /* FALSE - MINUS direction, TRUE - PLUS direction */
  Bool  ldefnext_dir = FALSE;
  Bool  first_time = FALSE;         /* first time flag then set to TRUE */
  Bool  secret_flag;            /* set if linedef is secret */


  if (*ldlist == NULL)
    return;

NEXT_LINE:

  /* get linedef number */
  ldef = (*ldlist)->objnum;

  /* Is there more than 1 LineDef selected? */
  if ((*ldlist)->next == NULL)
    {
      Beep();
      sprintf(errormessage, "More than 1 LineDef must be selected in sequence");
      Notify(-1, -1, errormessage, NULL);
      return;
    }

  /* Does sidedef exist? */
  if ((type_sd == FALSE && level->linedefs[ldef].sidedef1 == -1)
      || (type_sd == TRUE && level->linedefs[ldef].sidedef2 == -1))
    {
      Beep();
      if (type_sd == FALSE)
        sprintf(errormessage, "No sidedef 1 for LineDef #%d. Do you want to try Sidedef 2?", ldef);
      else
        sprintf(errormessage, "No sidedef 2 for LineDef #%d. Do you want to try Sidedef 1?", ldef);
      if (!Confirm(-1, -1, errormessage, NULL))
        return;
      /* toggle type_sd */
      type_sd = !type_sd;
      goto NEXT_LINE;
    }
  /* get next linedef number */
  ldefnext = (*ldlist)->next->objnum;

  if (type_sd == FALSE)
    {
      sdcur = level->linedefs[ldef].sidedef1;
    }
  else
    if (type_sd == TRUE)
      {
        sdcur = level->linedefs[ldef].sidedef2;
      }

  if (sdcur == -1)
    {
      Beep();
      sprintf(errormessage, "Sidedef = -1 for LineDef #%d.", ldef);
      Notify(-1, -1, errormessage, NULL);
      return;
    }


  /* get texture name of the SideDef in the *ldlist) */
  strncpy(uppertexname, level->sidedefs[sdcur].tex1, 8); /* upper texture */
  strncpy(lowertexname, level->sidedefs[sdcur].tex2, 8); /* lower texture */
  strncpy(normaltexname, level->sidedefs[sdcur].tex3, 8); /* normal texture */

  /* Does a texture exist? */
  if ((uppertexname[0] == '-' && lowertexname[0] == '-' && normaltexname[0] == '-'))
    {
       Beep();
       if (type_sd == FALSE)
         sprintf(errormessage, "No textures for sidedef 1 - #%d. Do you want to try Sidedef 2?", sdcur);
       else
         sprintf(errormessage, "No textures for sidedef 2 - #%d. Do you want to try Sidedef 1?", sdcur);
       if (!Confirm(-1, -1, errormessage, NULL))
         return;
       /* toggle type_sd */
       type_sd = !type_sd;
       goto NEXT_LINE;
    }

  /* FIND largest of upper,lower,and normal texture */
  texlength = 0;
  switch(MaxTexture)
    {
      case 0:
      case 3:
        {
          Int16 upper = 0, lower = 0;

          if (normaltexname[0] != '-')
            {
              strcpy(texname, normaltexname);
              GetWallTextureSize(&texlength, &dummy, normaltexname);
            }
          if (uppertexname[0] != '-')
            {
               strcpy(texname, uppertexname);
               GetWallTextureSize(&upper, &dummy, uppertexname);
            }
          if (lowertexname[0] != '-')
            {
              strcpy(texname, lowertexname);
              GetWallTextureSize(&lower, &dummy, lowertexname);
            }
          if (upper > texlength)
            {
              texlength = upper;
              strcpy(texname, uppertexname);
            }
          if (lower > texlength)
            {
              texlength = lower;
              strcpy(texname, lowertexname);
            }
        }
        break;
      case 1:       /* use Upper texture as largest */
        if (uppertexname[0] != '-')
          {
            strcpy(texname,uppertexname);
            GetWallTextureSize(&texlength, &dummy, uppertexname);
          }
        else
          {
            Beep();
            sprintf(errormessage, "Nu UPPER texture for sidedef #%d.", sdcur);
            Notify(-1, -1, errormessage, NULL);
            return;
          }
        break;
      case 2:      /* use Lower texture as largest */
        if (lowertexname[0] != '-')
          {
            strcpy(texname, lowertexname);
            GetWallTextureSize(&texlength, &dummy, lowertexname);
          }
        else
          {
            Beep();
            sprintf(errormessage, "No LOWER texture for sidedef #%d.", sdcur);
            Notify(-1, -1, errormessage, NULL);
            return;
          }
        break;
    }


  /* get initial offset to use (if required) */
  if (type_off == 1)
    {
      char prompt[80];  /* prompt for inital offset input */

      sprintf(prompt, "Enter initial offset between 0 and %d:", texlength);

      /* prompt for inital offset input */
      useroffset = InputIntegerValue(-1, -1, prompt, 0, texlength, 0);

      /* user pressed ESC key */
      if (useroffset == -32767)
        return;
    }

  while (*ldlist != NULL)  /* main processing loop */
    {
      /* get next sidedefs from next linedef */

      if ((*ldlist)->next == NULL) /* end of list */
        {
          if (!(level->linedefs[ldef].flags & 0x20))
            {
              level->sidedefs[sdcur].xoff = xoffset;
            }
          UnSelectObject(ldlist, (*ldlist)->objnum);
          break;
        }
      /* get next linedef number */
      ldefnext = (*ldlist)->next->objnum;
      /* get sidedef numbers from next linedef */
      side1 = level->linedefs[ldefnext].sidedef1;
      side2 = level->linedefs[ldefnext].sidedef2;

      /* determine direction of ldef and ldefnext */

      /* -----> -----> */
      /*   |      |    */
      if (level->linedefs[ldef].end == level->linedefs[ldefnext].start)
        {
          ldef_dir = TRUE;             /* TRUE - PLUS direction, TRUE - PLUS direction */
          ldefnext_dir = TRUE;
        }
      else
        /*           |   */
        /* -----> <----- */
        /*   |           */
        if (level->linedefs[ldef].end == level->linedefs[ldefnext].end)
          {
            ldef_dir = TRUE;          /* TRUE - PLUS direction, FALSE - MINUS direction */
            ldefnext_dir = FALSE;
          }
        else
          /*   |           */
          /* <----- -----> */
          /*          |    */
          if (level->linedefs[ldef].start == level->linedefs[ldefnext].start)
            {
              ldef_dir = FALSE;       /* FALSE - MINUS direction, TRUE - PLUS direction */
              ldefnext_dir = TRUE;
            }
          else
            /*   |       |   */
            /* <----- <----- */
            if (level->linedefs[ldef].start == level->linedefs[ldefnext].end)
              {
                ldef_dir = FALSE;    /* FALSE - MINUS direction, FALSE - MINUS direction */
                ldefnext_dir = FALSE;
              }
            else
              {
                UnSelectObject(ldlist, (*ldlist)->objnum);

                if (type_off == TRUE)
                  {
                    xoffset = useroffset;
                    type_off = FALSE; /* don't prompt for initial height */
                  }
                else
                  xoffset = FALSE;

                if (!Config.expert)
                  {
                    Beep();
                    sprintf(errormessage, "Starting next group with Linedef #%d.", (*ldlist)->objnum);
                    LogMessage(errormessage);
                    LogMessage("\n");
                    Notify(-1, -1, errormessage, NULL);
                  }

                goto NEXT_LINE;
              }

      /* 1----->2 */
      /*    |     */
      if (ldef_dir == TRUE)
        {
          vert1 = level->linedefs[ldef].start;
          vert2 = level->linedefs[ldef].end;
        }
      else
        {
          /*     |     */
          /* 1<----- 2 */
          vert1 = level->linedefs[ldef].end;
          vert2 = level->linedefs[ldef].start;
        }

      if (type_sd == FALSE)
        {
          if (ldef_dir == TRUE)   /* -----> */
            {                  /*   |    */
              if (ldefnext_dir == TRUE) /* -----> */
                {                     /*   |    */
                  sdnext = side1;
                  type_sd = FALSE;
                }                  /*    |   */
              else               /* <----- */
                {
                  sdnext = side2;
                  type_sd = TRUE;
                }
            }              /*    |   */
          else           /* <----- */
            {
              if (ldefnext_dir == TRUE)  /* -----> */
                {                      /*   |    */
                  sdnext = side2;
                  type_sd = TRUE;
                }                   /*    |   */
              else                /* <----- */
                {
                  sdnext = side1;
                  type_sd = FALSE;
                }
            }
        }
      else
        if (type_sd == TRUE)
          {
            if (ldef_dir == TRUE) /* -----> */
              {                 /*   |    */
                if (ldefnext_dir == TRUE) /* -----> */
                  {                     /*   |    */
                    sdnext = side2;
                    type_sd = TRUE;
                  }                  /*    |   */
                else               /* <----- */
                  {
                    sdnext = side1;
                    type_sd = FALSE;
                  }
              }              /*    |   */
            else           /* <----- */
              {
                if (ldefnext_dir == TRUE)  /* -----> */
                  {                      /*   |    */
                    sdnext = side1;
                    type_sd = FALSE;
                  }                   /*    |   */
                else                /* <----- */
                  {
                    sdnext = side2;
                    type_sd = TRUE;
                  }
              }
          }

      if (sdnext == -1)
        {
          Beep();
          sprintf(errormessage, "Sidedef = -1 for LineDef #%d.", ldef);
          Notify(-1, -1, errormessage, NULL);
          return;
        }
      /* do we test for same textures for the SideDef in question?? */
      if (type_tex == TRUE)
        {
          if (level->sidedefs[sdnext].tex3[0] != '-')  /* normal */
            {
              if (strncmp(level->sidedefs[sdnext].tex3, texname, 8))
                {
                  Beep();
                  sprintf(errormessage, "Different normal texture for SideDef #%d.", sdnext);
                  Notify(-1, -1, errormessage, NULL);
                  return;
                }
            }
          else       /* upper and lower */
            if (level->sidedefs[sdnext].tex1[0] != '-' && level->sidedefs[sdnext].tex2[0] != '-')
              {
                if (strncmp(level->sidedefs[sdnext].tex1, texname, 8)
                    || strncmp(level->sidedefs[sdnext].tex2, texname, 8))
                  {
                    Beep();
                    sprintf(errormessage, "Different upper or lower texture for SideDef #%d.", sdnext);
                    Notify(-1, -1, errormessage, NULL);
                    return;
                  }
              }
            else     /* upper only */
              if (level->sidedefs[sdnext].tex1[0] != '-')
                {
                  if (strncmp(level->sidedefs[sdnext].tex1, texname, 8))
                    {
                      Beep();
                      sprintf(errormessage, "Different upper texture for SideDef #%d.", sdnext);
                      Notify(-1, -1, errormessage, NULL);
                      return;
                    }
                }
              else  /* lower only */
                if (level->sidedefs[sdnext].tex2[0] != '-')
                  {
                    if (strncmp(level->sidedefs[sdnext].tex2, texname, 8))
                      {
                        Beep();
                        sprintf(errormessage, "Different lower texture for SideDef #%d.", sdnext);
                        Notify(-1, -1, errormessage, NULL);
                        return;
                      }
                  }
                else   /* ERROR - No textures!! */
                  {
                    Beep();
                    sprintf(errormessage, "Different lower texture for SideDef #%d.", sdnext);
                    Notify(-1, -1, errormessage, NULL);
                    return;
                  }
        }

      /* check secret linedef */
      secret_flag = FALSE;
      if ((level->linedefs[ldef].flags & 0x20))
        secret_flag = TRUE;

      /* is this the first time round here */
      /* put new xoffset into the SideDef */
      if (first_time == FALSE)
        {
          if (type_off == TRUE)  /* do we have an initial offset ? */
            {
              if (!secret_flag)
                level->sidedefs[sdcur].xoff = useroffset;
              xoffset = useroffset;
            }
          else
            if (!secret_flag)
              level->sidedefs[sdcur].xoff = xoffset;
        }
      else      /* put new xoffset into the SideDef */
        if (!secret_flag)
          level->sidedefs[sdcur].xoff = xoffset;

      first_time = TRUE;

      /* calculate length of LineDef */
      length = (Int16) (hypot((double) (level->vertexes[vert2].x - level->vertexes[vert1].x),
                              (double) (level->vertexes[vert2].y - level->vertexes[vert1].y))
                        + 0.5);
      xoffset += length;
      /* remove multiples of texlength from xoffset */
      xoffset = xoffset % texlength;

      /* move to next object in selected list */
      UnSelectObject(ldlist, (*ldlist)->objnum);
      sdcur = sdnext;
      ldef = ldefnext;
    }
  level->made_changes = TRUE;
}


/*
  ... ?
*/

void AlignTextures(LevelPtr level, SelPtr ldlist)
{
  /*!RQ to MM: why Int32 ??? */
  Int32 Align = FALSE;        /* FALSE - align x, TRUE - align y */
  Int32 StartFirst = FALSE;   /* FALSE - sidedef1, TRUE - sidedef2 */
  Int32 UseTexture = 0;       /* 0 is upper, 1 is lower, 2 is largest */
  Int32 MatchTextures = FALSE; /* If TRUE match textures */
  Int32 InitialOffset = FALSE; /* If TRUE get initial offset */
  Int32 AlignToFloor = FALSE;  /* If TRUE Align Lower Texture to Floor */
  Int32 SetUnpeg = FALSE;      /* If TRUE set unpeg flag */
  SelPtr newlist, cur;

  if (DrawDialogBox(-1, -1, 280, 260, NULL, 16,
                    DBSC_TEXT,   -0x0102, 8, '\0', "Align Textures", 0, RED,

                    DBSC_L_CHECKBOX, 24, 25,  'X', &Align, SVAL, FALSE, "Align X",
                    DBSC_L_CHECKBOX, 24, 40,  'Y', &Align, SVAL, TRUE, "Align Y",

                    DBSC_TEXT,       16, 56, '\0', "Start alignment with:", 0, YELLOW,
                    DBSC_L_CHECKBOX, 24, 72,  'F', &StartFirst, SVAL, FALSE, "First Sidedef",
                    DBSC_L_CHECKBOX, 24, 87,  'S', &StartFirst, SVAL, TRUE, "Second Sidedef",

                    DBSC_TEXT,       16, 103, '\0', "Prefered Texture:", 0, YELLOW,
                    DBSC_L_CHECKBOX, 24, 119,  'U', &UseTexture, SVAL,   1, "Upper",
                    DBSC_L_CHECKBOX, 24, 134,  'L', &UseTexture, SVAL,   2, "Lower",
                    DBSC_L_CHECKBOX, 24, 149,  'a', &UseTexture, SVAL,   3, "Largest",

                    DBSC_L_CHECKBOX, 24, 164,  'M', &MatchTextures, BIT, 0x1, "Match Textures",
                    DBSC_L_CHECKBOX, 24, 179,  'I', &InitialOffset, BIT, 0x1, "Enter initial offset",
                    DBSC_L_CHECKBOX, 24, 194,  'g', &AlignToFloor,  BIT, 0x1, "Align Lower Texture to Floor",
                    DBSC_L_CHECKBOX, 24, 209,  'P', &SetUnpeg,      BIT, 0x1, "Set Unpegged Flags",

                    DBSC_OK,             -0x0104, 239,  'O',
                    DBSC_CANCEL,         -0x0304, 239,  'C'))
    {

      /* copy FILO list (ldist) to FIFO list (newlist) */
      newlist = NULL;
      for (cur = ldlist; cur; cur = cur->next)
        SelectObject(&newlist, cur->objnum);

      if (Align == FALSE)  /* align X */
        AlignTexturesX(level, &newlist, (Bool)StartFirst, (Int8)UseTexture,
                         (Bool)MatchTextures, (Bool)InitialOffset);
      else /* align Y */
        AlignTexturesY(level, &newlist, (Bool)StartFirst, (Int8)UseTexture,
                         (Bool)InitialOffset, (Bool)AlignToFloor,
                         (Bool)SetUnpeg);

      /* free temporary list */
      ForgetSelection(&newlist);
    }
}



