home *** CD-ROM | disk | FTP | other *** search
/ Doom Fever / Doom_Fever-1995_Maple_Media.iso / wad / source.zip / EDITOBJ.C < prev    next >
C/C++ Source or Header  |  1994-05-20  |  81KB  |  2,678 lines

  1. /*
  2.    Doom Editor Utility, by Brendon Wyber and Raphaël Quinet.
  3.  
  4.    You are allowed to use any parts of this code in another program, as
  5.    long as you give credits to the authors in the documentation and in
  6.    the program itself.  Read the file README.1ST for more information.
  7.  
  8.    This program comes with absolutely no warranty.
  9.  
  10.    EDITOBJ.C - object editing routines.
  11. */
  12.  
  13. /* the includes */
  14. #include "deu.h"
  15. #include "levels.h"
  16.  
  17.  
  18. /*
  19.    display the information about one object
  20. */
  21.  
  22. void DisplayObjectInfo( int objtype, int objnum) /* SWAP! */
  23. {
  24.    char texname[ 9];
  25.    int  tag, n;
  26.    int  sd1, sd2, s1, s2;
  27.    int  x0, y0;
  28.  
  29.    ObjectsNeeded( objtype, 0);
  30.    switch (objtype)
  31.    {
  32.    case OBJ_THINGS:
  33.       x0 = 0;
  34.       y0 = ScrMaxY - 60;
  35.       if (InfoShown)
  36.      y0 -= 13;
  37.       DrawScreenBox3D( x0, y0, x0 + 260, y0 + 60);
  38.       if (objnum < 0)
  39.       {
  40.      DrawScreenText( x0 + 60, y0 + 20, "Use the cursor to");
  41.      DrawScreenText( x0 + 72, y0 + 30, "select a Thing  ");
  42.      break;
  43.       }
  44.       SetColor( YELLOW);
  45.       DrawScreenText( x0 + 5, y0 + 5, "Selected Thing (#%d)", objnum);
  46.       SetColor( BLACK);
  47.       DrawScreenText( -1, y0 + 20, "Coordinates:  (%d, %d)", Things[ objnum].xpos, Things[ objnum].ypos);
  48.       DrawScreenText( -1, -1, "Type:         %s", GetThingName( Things[ objnum].type));
  49.       DrawScreenText( -1, -1, "Angle:        %s", GetAngleName( Things[ objnum].angle));
  50.       DrawScreenText( -1, -1, "Appears when: %s", GetWhenName( Things[ objnum].when));
  51.       break;
  52.    case OBJ_LINEDEFS:
  53.       x0 = 0;
  54.       y0 = ScrMaxY - 80;
  55.       if (InfoShown)
  56.      y0 -= 13;
  57.       DrawScreenBox3D(   x0, y0, x0 + 218, y0 + 80);
  58.       if (objnum >= 0)
  59.       {
  60.      SetColor( YELLOW);
  61.      DrawScreenText( x0 + 5, y0 + 5, "Selected LineDef (#%d)", objnum);
  62.      SetColor( BLACK);
  63.      DrawScreenText( -1, y0 + 20, "Flags:%3d    %s", LineDefs[ objnum].flags, GetLineDefFlagsName( LineDefs[ objnum].flags));
  64.      DrawScreenText( -1, -1, "Type: %3d %s", LineDefs[ objnum].type, GetLineDefTypeName( LineDefs[ objnum].type));
  65.      sd1 = LineDefs[ objnum].sidedef1;
  66.      sd2 = LineDefs[ objnum].sidedef2;
  67.      tag = LineDefs[ objnum].tag;
  68.      s1 = LineDefs[ objnum].start;
  69.      s2 = LineDefs[ objnum].end;
  70.      ObjectsNeeded( OBJ_VERTEXES, 0);
  71.      n = ComputeDist( Vertexes[ s2].x - Vertexes[ s1].x, Vertexes[ s2].y - Vertexes[ s1].y);
  72.      DrawScreenText( x0 + 160, y0 + 60, "Length:");
  73.      DrawScreenText( x0 + 170, y0 + 70, "%d", n);
  74.      ObjectsNeeded( OBJ_SIDEDEFS, OBJ_SECTORS, 0);
  75.      if (tag > 0)
  76.      {
  77.         for (n = 0; n < NumSectors; n++)
  78.            if (Sectors[ n].tag == tag)
  79.           break;
  80.      }
  81.      else
  82.         n = NumSectors;
  83.      if (n < NumSectors)
  84.         DrawScreenText( x0 + 5, y0 + 40, "Sector tag:  %d (#%d)", tag, n);
  85.      else
  86.         DrawScreenText( x0 + 5, y0 + 40, "Sector tag:  %d (none)", tag);
  87.      DrawScreenText( -1, -1, "Vertexes:    (#%d, #%d)", s1, s2);
  88.      DrawScreenText( -1, -1, "1st SideDef: #%d", sd1);
  89.      DrawScreenText( -1, -1, "2nd SideDef: #%d", sd2);
  90.      if (sd1 >= 0)
  91.         s1 = SideDefs[ sd1].sector;
  92.      else
  93.         s1 = -1;
  94.      if (sd2 >= 0)
  95.         s2 = SideDefs[ sd2].sector;
  96.      else
  97.         s2 = -1;
  98.       }
  99.       else
  100.       {
  101.     SetColor( DARKGRAY);
  102.     DrawScreenText( x0 + 25, y0 + 35, "(No LineDef selected)");
  103.       }
  104.       x0 = 220;
  105.       y0 = ScrMaxY - 80;
  106.       if (InfoShown)
  107.      y0 -= 13;
  108.       DrawScreenBox3D( x0, y0, x0 + 218, y0 + 80);
  109.       if (objnum >= 0 && sd1 >= 0)
  110.       {
  111.      SetColor( YELLOW);
  112.      DrawScreenText( x0 + 5, y0 + 5, "First SideDef (#%d)", sd1);
  113.      SetColor( BLACK);
  114.      texname[ 8] = '\0';
  115.      strncpy( texname, SideDefs[ sd1].tex3, 8);
  116.      DrawScreenText( -1, y0 + 20, "Normal texture: %s", texname);
  117.      strncpy( texname, SideDefs[ sd1].tex1, 8);
  118.      if (s1 >= 0 && s2 >= 0 && Sectors[ s1].ceilh > Sectors[ s2].ceilh)
  119.      {
  120.         if (texname[ 0] == '-' && texname[ 1] == '\0')
  121.            SetColor( RED);
  122.      }
  123.      else
  124.         SetColor( DARKGRAY);
  125.      DrawScreenText( -1, -1, "Upper texture:  %s", texname);
  126.      SetColor( BLACK);
  127.      strncpy( texname, SideDefs[ sd1].tex2, 8);
  128.      if (s1 >= 0 && s2 >= 0 && Sectors[ s1].floorh < Sectors[ s2].floorh)
  129.      {
  130.         if (texname[ 0] == '-' && texname[ 1] == '\0')
  131.            SetColor( RED);
  132.      }
  133.      else
  134.         SetColor( DARKGRAY);
  135.      DrawScreenText( -1, -1, "Lower texture:  %s", texname);
  136.      SetColor( BLACK);
  137.      DrawScreenText( -1, -1, "Tex. X offset:  %d", SideDefs[ sd1].xoff);
  138.      DrawScreenText( -1, -1, "Tex. Y offset:  %d", SideDefs[ sd1].yoff);
  139.      DrawScreenText( -1, -1, "Sector:         #%d", s1);
  140.       }
  141.       else
  142.       {
  143.     SetColor( DARKGRAY);
  144.     DrawScreenText( x0 + 25, y0 + 35, "(No first SideDef)");
  145.       }
  146.       x0 = 440;
  147.       y0 = ScrMaxY - 80;
  148.       if (InfoShown)
  149.      y0 -= 13;
  150.       DrawScreenBox3D( x0, y0, x0 + 200, y0 + 80);
  151.       if (objnum >= 0 && sd2 >= 0)
  152.       {
  153.      SetColor( YELLOW);
  154.      DrawScreenText( x0 + 5, y0 + 5, "Second SideDef (#%d)", sd2);
  155.      SetColor( BLACK);
  156.      texname[ 8] = '\0';
  157.      strncpy( texname, SideDefs[ sd2].tex3, 8);
  158.      DrawScreenText( -1, y0 + 20, "Normal texture: %s", texname);
  159.      strncpy( texname, SideDefs[ sd2].tex1, 8);
  160.      if (s1 >= 0 && s2 >= 0 && Sectors[ s2].ceilh > Sectors[ s1].ceilh)
  161.      {
  162.         if (texname[ 0] == '-' && texname[ 1] == '\0')
  163.            SetColor( RED);
  164.      }
  165.      else
  166.         SetColor( DARKGRAY);
  167.      DrawScreenText( -1, -1, "Upper texture:  %s", texname);
  168.      SetColor( BLACK);
  169.      strncpy( texname, SideDefs[ sd2].tex2, 8);
  170.      if (s1 >= 0 && s2 >= 0 && Sectors[ s2].floorh < Sectors[ s1].floorh)
  171.      {
  172.         if (texname[ 0] == '-' && texname[ 1] == '\0')
  173.            SetColor( RED);
  174.      }
  175.      else
  176.         SetColor( DARKGRAY);
  177.      DrawScreenText( -1, -1, "Lower texture:  %s", texname);
  178.      SetColor( BLACK);
  179.      DrawScreenText( -1, -1, "Tex. X offset:  %d", SideDefs[ sd2].xoff);
  180.      DrawScreenText( -1, -1, "Tex. Y offset:  %d", SideDefs[ sd2].yoff);
  181.      DrawScreenText( -1, -1, "Sector:         #%d", s2);
  182.       }
  183.       else
  184.       {
  185.     SetColor( DARKGRAY);
  186.     DrawScreenText( x0 + 25, y0 + 35, "(No second SideDef)");
  187.       }
  188.       break;
  189.    case OBJ_VERTEXES:
  190.       x0 = 0;
  191.       y0 = ScrMaxY - 30;
  192.       if (InfoShown)
  193.      y0 -= 13;
  194.       DrawScreenBox3D( x0, y0, x0 + 220, y0 + 30);
  195.       if (objnum < 0)
  196.       {
  197.      SetColor( DARKGRAY);
  198.      DrawScreenText( x0 + 30, y0 + 12, "(No Vertex selected)");
  199.      break;
  200.       }
  201.       SetColor( YELLOW);
  202.       DrawScreenText( x0 + 5, y0 + 5, "Selected Vertex (#%d)", objnum);
  203.       SetColor( BLACK);
  204.       DrawScreenText( -1, y0 + 20, "Coordinates: (%d, %d)", Vertexes[ objnum].x, Vertexes[ objnum].y);
  205.       break;
  206.    case OBJ_SECTORS:
  207.       x0 = 0;
  208.       y0 = ScrMaxY - 90;
  209.       if (InfoShown)
  210.      y0 -= 13;
  211.       DrawScreenBox3D( x0, y0, x0 + 255, y0 + 90);
  212.       if (objnum < 0)
  213.       {
  214.     SetColor( DARKGRAY);
  215.     DrawScreenText( x0 + 48, y0 + 35, "(No Sector selected)");
  216.     break;
  217.       }
  218.       SetColor( YELLOW);
  219.       DrawScreenText( x0 + 5, y0 + 5, "Selected Sector (#%d)", objnum);
  220.       SetColor( BLACK);
  221.       DrawScreenText( -1, y0 + 20, "Floor height:    %d", Sectors[ objnum].floorh);
  222.       DrawScreenText( -1, -1, "Ceiling height:  %d", Sectors[ objnum].ceilh);
  223.       texname[ 8] = '\0';
  224.       strncpy( texname, Sectors[ objnum].floort, 8);
  225.       DrawScreenText( -1, -1, "Floor texture:   %s", texname);
  226.       strncpy( texname, Sectors[ objnum].ceilt, 8);
  227.       DrawScreenText( -1, -1, "Ceiling texture: %s", texname);
  228.       DrawScreenText( -1, -1, "Light level:     %d", Sectors[ objnum].light);
  229.       DrawScreenText( -1, -1, "Type: %3d        %s", Sectors[ objnum].special, GetSectorTypeName( Sectors[ objnum].special));
  230.       tag = Sectors[ objnum].tag;
  231.       ObjectsNeeded( OBJ_LINEDEFS, 0);
  232.       if (tag == 0)
  233.      n = NumLineDefs;
  234.       else
  235.      for (n = 0; n < NumLineDefs; n++)
  236.         if (LineDefs[ n].tag == tag)
  237.            break;
  238.       if (n < NumLineDefs)
  239.      DrawScreenText( -1, -1, "LineDef tag:     %d (#%d)", tag, n);
  240.       else if (tag == 99 || tag == 999)
  241.      DrawScreenText( -1, -1, "LineDef tag:     %d (stairs?)", tag);
  242.       else if (tag == 666)
  243.      DrawScreenText( -1, -1, "LineDef tag:     %d (lower@end)", tag);
  244.       else
  245.      DrawScreenText( -1, -1, "LineDef tag:     %d (none)", tag);
  246.       break;
  247.    }
  248. }
  249.  
  250.  
  251.  
  252. /*
  253.    display and execute a "things" menu
  254. */
  255.  
  256. int DisplayThingsMenu( int x0, int y0, char *menutitle, ...)
  257. {
  258.    va_list args;
  259.    int     val, num;
  260.    int     thingid[ 30];
  261.    char   *menustr[ 30];
  262.    int     dummy[ 30];
  263.  
  264.    /* put the va_args in the menustr table */
  265.    num = 0;
  266.    va_start( args, menutitle);
  267.    while ((num < 30) && ((thingid[ num] = va_arg( args, int)) >= 0))
  268.    {
  269.       menustr[ num] = GetThingName( thingid[ num]);
  270.       num++;
  271.    }
  272.    va_end( args);
  273.  
  274.    /* display the menu */
  275.    val = DisplayMenuArray( x0, y0, menutitle, num, NULL, menustr, dummy) - 1;
  276.  
  277.    /* return the thing id, if valid */
  278.    if (val < 0 || val >= num)
  279.      return -1;
  280.    return thingid[ val];
  281. }
  282.  
  283.  
  284.  
  285. /*
  286.    display and execute a "linedef type" menu
  287. */
  288.  
  289. int DisplayLineDefTypeMenu( int x0, int y0, char *menutitle, ...)
  290. {
  291.    va_list args;
  292.    int     val, num, n;
  293.    int     typeid[ 30];
  294.    char   *menustr[ 30];
  295.    int     dummy[ 30];
  296.  
  297.    /* put the va_args in the menustr table */
  298.    num = 0;
  299.    val = 0;
  300.    va_start( args, menutitle);
  301.    while ((num < 30) && ((typeid[ num] = va_arg( args, int)) >= 0))
  302.    {
  303.       menustr[ num] = GetMemory( 80 * sizeof( char));
  304.       sprintf( menustr[ num], "%-79s", GetLineDefTypeLongName( typeid[ num]));
  305.       if (strlen( GetLineDefTypeLongName( typeid[ num])) > val)
  306.          val = strlen( GetLineDefTypeLongName( typeid[ num]));
  307.       num++;
  308.    }
  309.    va_end( args);
  310.  
  311.    /* put the type numbers at the end of the lines */
  312.    for (n = 0; n < num; n++)
  313.       sprintf( menustr[ n] + val + 1, "[%3d]", typeid[ n]);
  314.  
  315.    /* display the menu */
  316.    val = DisplayMenuArray( x0, y0, menutitle, num, NULL, menustr, dummy) - 1;
  317.    for (n = 0; n < num; n++)
  318.       FreeMemory( menustr[ n]);
  319.  
  320.    /* return the thing id, if valid */
  321.    if (val < 0 || val >= num)
  322.      return -1;
  323.    return typeid[ val];
  324. }
  325.  
  326.  
  327.  
  328. /*
  329.    ask for an object number and check for maximum valid number
  330.    (this is just like InputIntegerValue, but with a different prompt)
  331. */
  332.  
  333. int InputObjectNumber( int x0, int y0, int objtype, int curobj)
  334. {
  335.    int val, key;
  336.    char prompt[ 80];
  337.  
  338.    if (UseMouse)
  339.       HideMousePointer();
  340.    sprintf( prompt, "Enter a %s number between 0 and %d:", GetObjectTypeName( objtype), GetMaxObjectNum( objtype));
  341.    if (x0 < 0)
  342.       x0 = (ScrMaxX - 25 - 8 * strlen( prompt)) / 2;
  343.    if (y0 < 0)
  344.       y0 = (ScrMaxY - 55) / 2;
  345.    DrawScreenBox3D( x0, y0, x0 + 25 + 8 * strlen( prompt), y0 + 55);
  346.    SetColor( WHITE);
  347.    DrawScreenText( x0 + 10, y0 + 8, prompt);
  348.    val = curobj;
  349.    while (((key = InputInteger( x0 + 10, y0 + 28, &val, 0, GetMaxObjectNum( objtype))) & 0x00FF) != 0x000D && (key & 0x00FF) != 0x001B)
  350.       Beep();
  351.    if (UseMouse)
  352.       ShowMousePointer();
  353.    return val;
  354. }
  355.  
  356.  
  357.  
  358. /*
  359.    ask for an object number and display a warning message
  360. */
  361.  
  362. int InputObjectXRef( int x0, int y0, int objtype, Bool allownone, int curobj)
  363. {
  364.    int val, key;
  365.    char prompt[ 80];
  366.  
  367.    if (UseMouse)
  368.       HideMousePointer();
  369.    sprintf( prompt, "Enter a %s number between 0 and %d%c", GetObjectTypeName( objtype), GetMaxObjectNum( objtype), allownone ? ',' : ':');
  370.    val = strlen( prompt);
  371.    if (val < 40)
  372.       val = 40;
  373.    if (x0 < 0)
  374.       x0 = (ScrMaxX - 25 - 8 * val) / 2;
  375.    if (y0 < 0)
  376.       y0 = (ScrMaxY - (allownone ? 85 : 75)) / 2;
  377.    DrawScreenBox3D( x0, y0, x0 + 25 + 8 * val, y0 + (allownone ? 85 : 75));
  378.    SetColor( WHITE);
  379.    DrawScreenText( x0 + 10, y0 + 8, prompt);
  380.    if (allownone)
  381.       DrawScreenText( x0 + 10, y0 + 18, "or -1 for none:");
  382.    SetColor( RED);
  383.    DrawScreenText( x0 + 10, y0 + (allownone ? 60 : 50), "Warning: modifying the cross-references");
  384.    DrawScreenText( x0 + 10, y0 + (allownone ? 70 : 60), "between some objects may crash the game.");
  385.    val = curobj;
  386.    while (((key = InputInteger( x0 + 10, y0 + (allownone ? 38 : 28), &val, allownone ? -1 : 0, GetMaxObjectNum( objtype))) & 0x00FF) != 0x000D && (key & 0x00FF) != 0x001B)
  387.       Beep();
  388.    if (UseMouse)
  389.       ShowMousePointer();
  390.    return val;
  391. }
  392.  
  393.  
  394.  
  395. /*
  396.    ask for two vertex numbers and check for maximum valid number
  397. */
  398.  
  399. Bool Input2VertexNumbers( int x0, int y0, char *prompt1, int *v1, int *v2)
  400. {
  401.    int  key;
  402.    int  maxlen, first;
  403.    Bool ok;
  404.    char prompt2[ 80];
  405.  
  406.    if (UseMouse)
  407.       HideMousePointer();
  408.    sprintf( prompt2, "Enter two numbers between 0 and %d:", NumVertexes - 1);
  409.    if (strlen( prompt1) > strlen( prompt2))
  410.       maxlen = strlen( prompt1);
  411.    else
  412.       maxlen = strlen( prompt2);
  413.    if (x0 < 0)
  414.       x0 = (ScrMaxX - 25 - 8 * maxlen) / 2;
  415.    if (y0 < 0)
  416.       y0 = (ScrMaxY - 75) / 2;
  417.    DrawScreenBox3D( x0, y0, x0 + 25 + 8 * maxlen, y0 + 75);
  418.    DrawScreenText( x0 + 10, y0 + 36, "From this Vertex");
  419.    DrawScreenText( x0 + 180, y0 + 36, "To this Vertex");
  420.    SetColor( WHITE);
  421.    DrawScreenText( x0 + 10, y0 + 8, prompt1);
  422.    DrawScreenText( x0 + 10, y0 + 18, prompt2);
  423.    first = TRUE;
  424.    key = 0;
  425.    for (;;)
  426.    {
  427.       ok = TRUE;
  428.       DrawScreenBox3D( x0 + 10, y0 + 48, x0 + 71, y0 + 61);
  429.       if (*v1 < 0 || *v1 >= NumVertexes)
  430.       {
  431.      SetColor( DARKGRAY);
  432.      ok = FALSE;
  433.       }
  434.       DrawScreenText( x0 + 14, y0 + 51, "%d", *v1);
  435.       DrawScreenBox3D( x0 + 180, y0 + 48, x0 + 241, y0 + 61);
  436.       if (*v2 < 0 || *v2 >= NumVertexes)
  437.       {
  438.      SetColor( DARKGRAY);
  439.      ok = FALSE;
  440.       }
  441.       DrawScreenText( x0 + 184, y0 + 51, "%d", *v2);
  442.       if (first)
  443.      key = InputInteger( x0 + 10, y0 + 48, v1, 0, NumVertexes - 1);
  444.       else
  445.      key = InputInteger( x0 + 180, y0 + 48, v2, 0, NumVertexes - 1);
  446.       if ((key & 0xFF00) == 0x4B00 || (key & 0xFF00) == 0x4D00 || (key & 0x00FF) == 0x0009 || (key & 0xFF00) == 0x0F00)
  447.      first = !first;
  448.       else if ((key & 0x00FF) == 0x001B)
  449.      break;
  450.       else if ((key & 0x00FF) == 0x000D)
  451.       {
  452.      if (first)
  453.         first = FALSE;
  454.      else if (ok)
  455.         break;
  456.      else
  457.         Beep();
  458.       }
  459.       else
  460.      Beep();
  461.    }
  462.    if (UseMouse)
  463.       ShowMousePointer();
  464.    return ((key & 0x00FF) == 0x000D);
  465. }
  466.  
  467.  
  468.  
  469. /*
  470. */
  471.  
  472. char *GetTaggedLineDefFlag( int linedefnum, int flagndx)
  473. {
  474.    static char ldstr[ 9][ 50];
  475.  
  476.    if ((LineDefs[ linedefnum].flags & (0x01 << (flagndx - 1))) != 0)
  477.       strcpy( ldstr[ flagndx - 1], "\04 ");
  478.    else
  479.       strcpy( ldstr[ flagndx - 1], "  ");
  480.    strcat( ldstr[ flagndx - 1], GetLineDefFlagsLongName( 0x01 << (flagndx - 1)));
  481.    return ldstr[ flagndx - 1];
  482. }
  483.  
  484.  
  485.  
  486. /*
  487.    edit an object or a group of objects
  488. */
  489.  
  490. void EditObjectsInfo( int x0, int y0, int objtype, SelPtr obj) /* SWAP! */
  491. {
  492.    char  *menustr[ 30];
  493.    int    dummy[ 30];
  494.    char   texname[ 9];
  495.    int    n, val;
  496.    SelPtr cur, sdlist;
  497.  
  498.    ObjectsNeeded( objtype, 0);
  499.    if (obj == NULL)
  500.       return;
  501.    switch (objtype)
  502.    {
  503.    case OBJ_THINGS:
  504.       for (n = 0; n < 6; n++)
  505.      menustr[ n] = GetMemory( 60);
  506.       sprintf( menustr[ 5], "Edit Thing #%d", obj->objnum);
  507.       sprintf( menustr[ 0], "Change Type          (Current: %s)", GetThingName( Things[ obj->objnum].type));
  508.       sprintf( menustr[ 1], "Change Angle         (Current: %s)", GetAngleName( Things[ obj->objnum].angle));
  509.       sprintf( menustr[ 2], "Change When Appears  (Current: %s)", GetWhenName( Things[ obj->objnum].when));
  510.       sprintf( menustr[ 3], "Change X position    (Current: %d)", Things[ obj->objnum].xpos);
  511.       sprintf( menustr[ 4], "Change Y position    (Current: %d)", Things[ obj->objnum].ypos);
  512.       val = DisplayMenuArray( x0, y0, menustr[ 5], 5, NULL, menustr, dummy);
  513.       for (n = 0; n < 6; n++)
  514.      FreeMemory( menustr[ n]);
  515.       switch (val)
  516.       {
  517.       case 1:
  518.      switch (DisplayMenu( x0 + 42, y0 + 34, "Select Class",
  519.                   "Player",
  520.                   "Enemy",
  521.                   "Weapon",
  522.                   "Bonus",
  523.                   "Decoration",
  524.                   "Decoration (light sources)",
  525.                   "Decoration (dead bodies)",
  526.                   "Decoration (hanging bodies)",
  527.                   "Teleport landing",
  528.                   "(Enter a decimal value)",
  529.                   NULL))
  530.      {
  531.      case 1:
  532.         val = DisplayThingsMenu( x0 + 84, y0 + 68, "Select Start Position Type",
  533.                      THING_PLAYER1,
  534.                      THING_PLAYER2,
  535.                      THING_PLAYER3,
  536.                      THING_PLAYER4,
  537.                      THING_DEATHMATCH,
  538.                      -1);
  539.         break;
  540.  
  541.      case 2:
  542.         val = DisplayThingsMenu( x0 + 84, y0 + 78, "Select Enemy",
  543.                      THING_TROOPER,
  544.                      THING_SARGEANT,
  545.                      THING_IMP,
  546.                      THING_DEMON,
  547.                      THING_SPECTOR,
  548.                      THING_BARON,
  549.                      THING_LOSTSOUL,
  550.                      THING_CACODEMON,
  551.                      THING_CYBERDEMON,
  552.                      THING_SPIDERBOSS,
  553.                      -1);
  554.         break;
  555.  
  556.      case 3:
  557.         val = DisplayThingsMenu( x0 + 84, y0 + 88, "Select Weapon",
  558.                      THING_SHOTGUN,
  559.                      THING_CHAINGUN,
  560.                      THING_LAUNCHER,
  561.                      THING_PLASMAGUN,
  562.                      THING_CHAINSAW,
  563.                      THING_SHELLS,
  564.                      THING_AMMOCLIP,
  565.                      THING_ROCKET,
  566.                      THING_ENERGYCELL,
  567.                      THING_BFG9000,
  568.                      THING_SHELLBOX,
  569.                      THING_AMMOBOX,
  570.                      THING_ROCKETBOX,
  571.                      THING_ENERGYPACK,
  572.                      THING_BACKPACK,
  573.                      -1);
  574.         break;
  575.  
  576.      case 4:
  577.         val = DisplayThingsMenu( x0 + 84, y0 + 98, "Select Bonus",
  578.                      THING_REDCARD,
  579.                      THING_YELLOWCARD,
  580.                      THING_BLUECARD,
  581.                      THING_REDSKULLKEY,
  582.                      THING_YELLOWSKULLKEY,
  583.                      THING_BLUESKULLKEY,
  584.                      THING_ARMBONUS1,
  585.                      THING_GREENARMOR,
  586.                      THING_BLUEARMOR,
  587.                      THING_HLTBONUS1,
  588.                      THING_STIMPACK,
  589.                      THING_MEDKIT,
  590.                      THING_SOULSPHERE,
  591.                      THING_BLURSPHERE,
  592.                      THING_MAP,
  593.                      THING_RADSUIT,
  594.                      THING_LITEAMP,
  595.                      THING_BESERK,
  596.                      THING_INVULN,
  597.                      -1);
  598.         break;
  599.  
  600.      case 5:
  601.         val = DisplayThingsMenu( x0 + 84, y0 + 108, "Select Decoration",
  602.                      THING_BARREL,
  603.                      THING_TECHCOLUMN,
  604.                      THING_TGREENPILLAR,
  605.                      THING_TREDPILLAR,
  606.                      THING_SGREENPILLAR,
  607.                      THING_SREDPILLAR,
  608.                      THING_PILLARHEART,
  609.                      THING_PILLARSKULL,
  610.                      THING_EYEINSYMBOL,
  611.                      THING_BROWNSTUB,
  612.                      THING_GREYTREE,
  613.                      THING_BROWNTREE,
  614.                      -1);
  615.         break;
  616.  
  617.      case 6:
  618.         val = DisplayThingsMenu( x0 + 84, y0 + 118, "Select Decoration",
  619.                      THING_CANDLE,
  620.                      THING_LAMP,
  621.                      THING_CANDELABRA,
  622.                      THING_TBLUETORCH,
  623.                      THING_TGREENTORCH,
  624.                      THING_TREDTORCH,
  625.                      THING_SBLUETORCH,
  626.                      THING_SGREENTORCH,
  627.                      THING_SREDTORCH,
  628.                      -1);
  629.         break;
  630.  
  631.      case 7:
  632.         val = DisplayThingsMenu( x0 + 84, y0 + 128, "Select Decoration",
  633.                      THING_DEADPLAYER,
  634.                      THING_DEADTROOPER,
  635.                      THING_DEADSARGEANT,
  636.                      THING_DEADIMP,
  637.                      THING_DEADDEMON,
  638.                      THING_DEADCACODEMON,
  639.                      THING_BONES,
  640.                      THING_BONES2,
  641.                      THING_POOLOFBLOOD,
  642.                      THING_SKULLTOPPOLE,
  643.                      THING_HEADSKEWER,
  644.                      THING_PILEOFSKULLS,
  645.                      THING_IMPALEDBODY,
  646.                      THING_IMPALEDBODY2,
  647.                      THING_SKULLSINFLAMES,
  648.                      -1);
  649.         break;
  650.  
  651.      case 8:
  652.         val = DisplayThingsMenu( x0 + 84, y0 + 138, "Select Decoration",
  653.                      THING_HANGINGSWAYING,
  654.                      THING_HANGINGARMSOUT,
  655.                      THING_HANGINGONELEG,
  656.                      THING_HANGINGTORSO,
  657.                      THING_HANGINGLEG,
  658.                      THING_HANGINGSWAYING2,
  659.                      THING_HANGINGARMSOUT2,
  660.                      THING_HANGINGONELEG2,
  661.                      THING_HANGINGTORSO2,
  662.                      THING_HANGINGLEG2,
  663.                      -1);
  664.         break;
  665.  
  666.      case 9:
  667.         val = THING_TELEPORT;
  668.         break;
  669.  
  670.      case 10:
  671.         val = InputIntegerValue( x0 + 84, y0 + 158, 0, 9999, Things[ obj->objnum].type);
  672.         break;
  673.  
  674.      default:
  675.         Beep();
  676.         return;
  677.      }
  678.      if (val >= 0)
  679.      {
  680.         for (cur = obj; cur; cur = cur->next)
  681.            Things[ cur->objnum].type = val;
  682.         MadeChanges = TRUE;
  683.      }
  684.      break;
  685.  
  686.       case 2:
  687.      switch (DisplayMenu( x0 + 42, y0 + 44, "Select Angle",
  688.                   "North",
  689.                   "NorthEast",
  690.                   "East",
  691.                   "SouthEast",
  692.                   "South",
  693.                   "SouthWest",
  694.                   "West",
  695.                   "NorthWest",
  696.                   NULL))
  697.      {
  698.      case 1:
  699.         for (cur = obj; cur; cur = cur->next)
  700.            Things[ cur->objnum].angle = 90;
  701.         MadeChanges = TRUE;
  702.         break;
  703.      case 2:
  704.         for (cur = obj; cur; cur = cur->next)
  705.            Things[ cur->objnum].angle = 45;
  706.         MadeChanges = TRUE;
  707.         break;
  708.      case 3:
  709.         for (cur = obj; cur; cur = cur->next)
  710.            Things[ cur->objnum].angle = 0;
  711.         MadeChanges = TRUE;
  712.         break;
  713.      case 4:
  714.         for (cur = obj; cur; cur = cur->next)
  715.            Things[ cur->objnum].angle = 315;
  716.         MadeChanges = TRUE;
  717.         break;
  718.      case 5:
  719.         for (cur = obj; cur; cur = cur->next)
  720.            Things[ cur->objnum].angle = 270;
  721.         MadeChanges = TRUE;
  722.         break;
  723.      case 6:
  724.         for (cur = obj; cur; cur = cur->next)
  725.            Things[ cur->objnum].angle = 225;
  726.         MadeChanges = TRUE;
  727.         break;
  728.      case 7:
  729.         for (cur = obj; cur; cur = cur->next)
  730.            Things[ cur->objnum].angle = 180;
  731.         MadeChanges = TRUE;
  732.         break;
  733.      case 8:
  734.         for (cur = obj; cur; cur = cur->next)
  735.            Things[ cur->objnum].angle = 135;
  736.         MadeChanges = TRUE;
  737.         break;
  738.      }
  739.      break;
  740.  
  741.       case 3:
  742.      val = DisplayMenu( x0 + 42, y0 + 54, "Choose the difficulty level(s)",
  743.                 "D12          (Easy only)",
  744.                 "D3           (Medium only)",
  745.                 "D12, D3      (Easy and Medium)",
  746.                 "D45          (Hard only)",
  747.                 "D12, D45     (Easy and Hard)",
  748.                 "D3, D45      (Medium and Hard)",
  749.                 "D12, D3, D45 (Easy, Medium, Hard)",
  750.                 "Toggle \"Deaf/Ambush\" bit",
  751.                 "Toggle \"Multi-player only\" bit",
  752.                 "(Enter a decimal value)",
  753.                 NULL);
  754.      switch (val)
  755.      {
  756.      case 1:
  757.      case 2:
  758.      case 3:
  759.      case 4:
  760.      case 5:
  761.      case 6:
  762.      case 7:
  763.         for (cur = obj; cur; cur = cur->next)
  764.            Things[ cur->objnum].when = (Things[ cur->objnum].when & 0x18) | val;
  765.         MadeChanges = TRUE;
  766.         break;
  767.      case 8:
  768.         for (cur = obj; cur; cur = cur->next)
  769.            Things[ cur->objnum].when ^= 0x08;
  770.         MadeChanges = TRUE;
  771.         break;
  772.      case 9:
  773.         for (cur = obj; cur; cur = cur->next)
  774.            Things[ cur->objnum].when ^= 0x10;
  775.         MadeChanges = TRUE;
  776.         break;
  777.      case 10:
  778.         val = InputIntegerValue( x0 + 84, y0 + 158, 1, 31, Things[ obj->objnum].when);
  779.         if (val > 0)
  780.         {
  781.            for (cur = obj; cur; cur = cur->next)
  782.           Things[ cur->objnum].when = val;
  783.            MadeChanges = TRUE;
  784.         }
  785.         break;
  786.      }
  787.      break;
  788.  
  789.       case 4:
  790.      val = InputIntegerValue( x0 + 42, y0 + 64, MapMinX, MapMaxX, Things[ obj->objnum].xpos);
  791.      if (val >= MapMinX)
  792.      {
  793.         n = val - Things[ obj->objnum].xpos;
  794.         for (cur = obj; cur; cur = cur->next)
  795.            Things[ cur->objnum].xpos += n;
  796.         MadeChanges = TRUE;
  797.      }
  798.      break;
  799.  
  800.       case 5:
  801.      val = InputIntegerValue( x0 + 42, y0 + 74, MapMinY, MapMaxY, Things[ obj->objnum].ypos);
  802.      if (val >= MapMinY)
  803.      {
  804.         n = val - Things[ obj->objnum].ypos;
  805.         for (cur = obj; cur; cur = cur->next)
  806.            Things[ cur->objnum].ypos += n;
  807.         MadeChanges = TRUE;
  808.      }
  809.      break;
  810.       }
  811.       break;
  812.  
  813.    case OBJ_VERTEXES:
  814.       for (n = 0; n < 3; n++)
  815.      menustr[ n] = GetMemory( 60);
  816.       sprintf( menustr[ 2], "Edit Vertex #%d", obj->objnum);
  817.       sprintf( menustr[ 0], "Change X position (Current: %d)", Vertexes[ obj->objnum].x);
  818.       sprintf( menustr[ 1], "Change Y position (Current: %d)", Vertexes[ obj->objnum].y);
  819.       val = DisplayMenuArray( 0, 30, menustr[ 2], 2, NULL, menustr, dummy);
  820.       for (n = 0; n < 3; n++)
  821.      FreeMemory( menustr[ n]);
  822.       switch (val)
  823.       {
  824.       case 1:
  825.      val = InputIntegerValue( x0 + 42, y0 + 34, min( MapMinX, -10000), max( MapMaxX, 10000), Vertexes[ obj->objnum].x);
  826.      if (val >= min( MapMinX, -10000))
  827.      {
  828.         n = val - Vertexes[ obj->objnum].x;
  829.         for (cur = obj; cur; cur = cur->next)
  830.            Vertexes[ cur->objnum].x += n;
  831.         MadeChanges = TRUE;
  832.         MadeMapChanges = TRUE;
  833.      }
  834.      break;
  835.  
  836.       case 2:
  837.      val = InputIntegerValue( x0 + 42, y0 + 44, min( MapMinY, -10000), max( MapMaxY, 10000), Vertexes[ obj->objnum].y);
  838.      if (val >= min( MapMinY, -10000))
  839.      {
  840.         n = val - Vertexes[ obj->objnum].y;
  841.         for (cur = obj; cur; cur = cur->next)
  842.            Vertexes[ cur->objnum].y += n;
  843.         MadeChanges = TRUE;
  844.         MadeMapChanges = TRUE;
  845.      }
  846.      break;
  847.       }
  848.       break;
  849.  
  850.    case OBJ_LINEDEFS:
  851.       switch (DisplayMenu( x0, y0, "Choose the object to edit:",
  852.                "Edit the LineDef",
  853.                (LineDefs[ obj->objnum].sidedef1 >= 0) ? "Edit the 1st SideDef" : "Add a 1st SideDef",
  854.                (LineDefs[ obj->objnum].sidedef2 >= 0) ? "Edit the 2nd SideDef" : "Add a 2nd SideDef",
  855.                NULL))
  856.       {
  857.       case 1:
  858.      for (n = 0; n < 8; n++)
  859.         menustr[ n] = GetMemory( 60);
  860.      sprintf( menustr[ 7], "Edit LineDef #%d", obj->objnum);
  861.      sprintf( menustr[ 0], "Change Flags            (Current: %d)", LineDefs[ obj->objnum].flags);
  862.      sprintf( menustr[ 1], "Change Type             (Current: %d)", LineDefs[ obj->objnum].type);
  863.      sprintf( menustr[ 2], "Change Sector tag       (Current: %d)", LineDefs[ obj->objnum].tag);
  864.      sprintf( menustr[ 3], "Change Starting Vertex  (Current: #%d)", LineDefs[ obj->objnum].start);
  865.      sprintf( menustr[ 4], "Change Ending Vertex    (Current: #%d)", LineDefs[ obj->objnum].end);
  866.      sprintf( menustr[ 5], "Change 1st SideDef ref. (Current: #%d)", LineDefs[ obj->objnum].sidedef1);
  867.      sprintf( menustr[ 6], "Change 2nd SideDef ref. (Current: #%d)", LineDefs[ obj->objnum].sidedef2);
  868.      val = DisplayMenuArray( x0 + 42, y0 + 34, menustr[ 7], 7, NULL, menustr, dummy);
  869.      for (n = 0; n < 8; n++)
  870.         FreeMemory( menustr[ n]);
  871.      switch (val)
  872.      {
  873.      case 1:
  874.         val = DisplayMenu( x0 + 84, y0 + 68, "Toggle the flags:",
  875.                    GetTaggedLineDefFlag( obj->objnum, 1),
  876.                    GetTaggedLineDefFlag( obj->objnum, 2),
  877.                    GetTaggedLineDefFlag( obj->objnum, 3),
  878.                    GetTaggedLineDefFlag( obj->objnum, 4),
  879.                    GetTaggedLineDefFlag( obj->objnum, 5),
  880.                    GetTaggedLineDefFlag( obj->objnum, 6),
  881.                    GetTaggedLineDefFlag( obj->objnum, 7),
  882.                    GetTaggedLineDefFlag( obj->objnum, 8),
  883.                    GetTaggedLineDefFlag( obj->objnum, 9),
  884.                    "(Enter a decimal value)",
  885.                    NULL);
  886.         if (val >= 1 && val <= 9)
  887.         {
  888.            for (cur = obj; cur; cur = cur->next)
  889.           LineDefs[ cur->objnum].flags ^= 0x01 << (val - 1);
  890.            MadeChanges = TRUE;
  891.         }
  892.         else if (val == 10)
  893.         {
  894.            val = InputIntegerValue( x0 + 126, y0 + 182, 0, 511, LineDefs[ obj->objnum].flags);
  895.            if (val >= 0)
  896.            {
  897.           for (cur = obj; cur; cur = cur->next)
  898.              LineDefs[ cur->objnum].flags = val;
  899.           MadeChanges = TRUE;
  900.            }
  901.         }
  902.         break;
  903.      case 2:
  904.         switch (DisplayMenu( x0 + 84, y0 + 78, "Choose a LineDef type:",
  905.                  "Normal",
  906.                  "Doors...",
  907.                  "Ceilings...",
  908.                  "Floors (raise)...",
  909.                  "Floors (lower)...",
  910.                  "Lifts & Moving things...",
  911.                  "Special...",
  912.                  "(Enter a decimal value)",
  913.                  NULL))
  914.         {
  915.         case 1:
  916.            val = 0;
  917.            break;
  918.         case 2:
  919.            val = DisplayLineDefTypeMenu( x0 + 126, y0 + 122, NULL, /* Doors */
  920.                          1, 26, 27, 28, 63, 29, 90, 4, 31, 32, 34, 33, 61, 103, 50, 86, 2, 46, 42, 75, 3, 76, 16,
  921.                          -1);
  922.            break;
  923.         case 3:
  924.            val = DisplayLineDefTypeMenu( x0 + 126, y0 + 132, NULL, /* Ceilings */
  925.                          43, 41, 72, 44, 40,
  926.                          -1);
  927.            break;
  928.         case 4:
  929.            val = DisplayLineDefTypeMenu( x0 + 126, y0 + 142, NULL, /* Floors (raise) */
  930.                          69, 18, 20, 22, 95, 47, 5, 14, 30, 93, 59, 66, 67, 15, 92, 58, 96, 64, 101, 91, 24, 65, 94, 56,
  931.                          -1);
  932.            break;
  933.         case 5:
  934.            val = DisplayLineDefTypeMenu( x0 + 126, y0 + 142, NULL, /* Floors (lower) */
  935.                          45, 60, 102, 82, 83, 19, 38, 70, 71, 98, 36, 23, 84, 68, 37, 9, 21,
  936.                          -1);
  937.            break;
  938.         case 6:
  939.            val = DisplayLineDefTypeMenu( x0 + 126, y0 + 152, NULL, /* Lifts & Moving things */
  940.                          62, 88, 10, 77, 6, 73, 74, 57, 87, 53, 89, 54, 7, 8,
  941.                          -1);
  942.            break;
  943.         case 7:
  944.            val = DisplayLineDefTypeMenu( x0 + 126, y0 + 162, NULL, /* Special */
  945.                          48, 11, 52, 51, 97, 39, 81, 13, 79, 35, 80, 12, 104, 17,
  946.                          -1);
  947.            break;
  948.         case 8:
  949.            val = InputIntegerValue( x0 + 126, y0 + 172, 0, 255, LineDefs[ obj->objnum].type);
  950.            break;
  951.         default:
  952.            val = -1;
  953.         }
  954.         if (val >= 0)
  955.         {
  956.            for (cur = obj; cur; cur = cur->next)
  957.           LineDefs[ cur->objnum].type = val;
  958.            MadeChanges = TRUE;
  959.         }
  960.         break;
  961.      case 3:
  962.         val = InputIntegerValue( x0 + 84, y0 + 88, 0, 255, LineDefs[ obj->objnum].tag);
  963.         if (val >= 0)
  964.         {
  965.            for (cur = obj; cur; cur = cur->next)
  966.           LineDefs[ cur->objnum].tag = val;
  967.            MadeChanges = TRUE;
  968.         }
  969.         break;
  970.      case 4:
  971.         val = InputObjectXRef( x0 + 84, y0 + 98, OBJ_VERTEXES, FALSE, LineDefs[ obj->objnum].start);
  972.         if (val >= 0)
  973.         {
  974.            for (cur = obj; cur; cur = cur->next)
  975.           LineDefs[ cur->objnum].start = val;
  976.            MadeChanges = TRUE;
  977.            MadeMapChanges = TRUE;
  978.         }
  979.         break;
  980.      case 5:
  981.         val = InputObjectXRef( x0 + 84, y0 + 108, OBJ_VERTEXES, FALSE, LineDefs[ obj->objnum].end);
  982.         if (val >= 0)
  983.         {
  984.            for (cur = obj; cur; cur = cur->next)
  985.           LineDefs[ cur->objnum].end = val;
  986.            MadeChanges = TRUE;
  987.            MadeMapChanges = TRUE;
  988.         }
  989.         break;
  990.      case 6:
  991.         val = InputObjectXRef( x0 + 84, y0 + 118, OBJ_SIDEDEFS, TRUE, LineDefs[ obj->objnum].sidedef1);
  992.         if (val >= -1)
  993.         {
  994.            for (cur = obj; cur; cur = cur->next)
  995.           LineDefs[ cur->objnum].sidedef1 = val;
  996.            MadeChanges = TRUE;
  997.            MadeMapChanges = TRUE;
  998.         }
  999.         break;
  1000.      case 7:
  1001.         val = InputObjectXRef( x0 + 84, y0 + 128, OBJ_SIDEDEFS, TRUE, LineDefs[ obj->objnum].sidedef2);
  1002.         if (val >= -1)
  1003.         {
  1004.            for (cur = obj; cur; cur = cur->next)
  1005.           LineDefs[ cur->objnum].sidedef2 = val;
  1006.            MadeChanges = TRUE;
  1007.            MadeMapChanges = TRUE;
  1008.         }
  1009.         break;
  1010.      }
  1011.      break;
  1012.  
  1013.       /* edit or add the first SideDef */
  1014.       case 2:
  1015.      ObjectsNeeded( OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
  1016.      if (LineDefs[ obj->objnum].sidedef1 >= 0)
  1017.      {
  1018.         /* build a new selection list with the first SideDefs */
  1019.         objtype = OBJ_SIDEDEFS;
  1020.         sdlist = NULL;
  1021.         for (cur = obj; cur; cur = cur->next)
  1022.            if (LineDefs[ cur->objnum].sidedef1 >= 0)
  1023.           SelectObject( &sdlist, LineDefs[ cur->objnum].sidedef1);
  1024.      }
  1025.      else
  1026.      {
  1027.         /* add a new first SideDef */
  1028.         for (cur = obj; cur; cur = cur->next)
  1029.            if (LineDefs[ cur->objnum].sidedef1 == -1)
  1030.            {
  1031.           InsertObject( OBJ_SIDEDEFS, -1, 0, 0);
  1032.           LineDefs[ cur->objnum].sidedef1 = NumSideDefs - 1;
  1033.            }
  1034.         break;
  1035.      }
  1036.      /* no break here */
  1037.  
  1038.       /* edit or add the second SideDef */
  1039.       case 3:
  1040.      if (objtype != OBJ_SIDEDEFS)
  1041.      {
  1042.         if (LineDefs[ obj->objnum].sidedef2 >= 0)
  1043.         {
  1044.            /* build a new selection list with the second (or first) SideDefs */
  1045.            objtype = OBJ_SIDEDEFS;
  1046.            sdlist = NULL;
  1047.            for (cur = obj; cur; cur = cur->next)
  1048.           if (LineDefs[ cur->objnum].sidedef2 >= 0)
  1049.              SelectObject( &sdlist, LineDefs[ cur->objnum].sidedef2);
  1050.           else if (LineDefs[ cur->objnum].sidedef1 >= 0)
  1051.              SelectObject( &sdlist, LineDefs[ cur->objnum].sidedef1);
  1052.         }
  1053.         else
  1054.         {
  1055.            /* add a new second (or first) SideDef */
  1056.            for (cur = obj; cur; cur = cur->next)
  1057.           if (LineDefs[ cur->objnum].sidedef1 == -1)
  1058.           {
  1059.              InsertObject( OBJ_SIDEDEFS, -1, 0, 0);
  1060.              ObjectsNeeded( OBJ_LINEDEFS, 0);
  1061.              LineDefs[ cur->objnum].sidedef1 = NumSideDefs - 1;
  1062.           }
  1063.           else if (LineDefs[ cur->objnum].sidedef2 == -1)
  1064.           {
  1065.              n = LineDefs[ cur->objnum].sidedef1;
  1066.              InsertObject( OBJ_SIDEDEFS, -1, 0, 0);
  1067.              strncpy( SideDefs[ NumSideDefs - 1].tex3, "-", 8);
  1068.              strncpy( SideDefs[ n].tex3, "-", 8);
  1069.              ObjectsNeeded( OBJ_LINEDEFS, 0);
  1070.              LineDefs[ cur->objnum].sidedef2 = NumSideDefs - 1;
  1071.              LineDefs[ cur->objnum].flags = 4;
  1072.           }
  1073.            break;
  1074.         }
  1075.      }
  1076.      ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1077.      for (n = 0; n < 7; n++)
  1078.         menustr[ n] = GetMemory( 60);
  1079.      sprintf( menustr[ 6], "Edit SideDef #%d", sdlist->objnum);
  1080.      texname[ 8] = '\0';
  1081.      strncpy( texname, SideDefs[ sdlist->objnum].tex3, 8);
  1082.      sprintf( menustr[ 0], "Change Normal Texture   (Current: %s)", texname);
  1083.      strncpy( texname, SideDefs[ sdlist->objnum].tex1, 8);
  1084.      sprintf( menustr[ 1], "Change Upper texture    (Current: %s)", texname);
  1085.      strncpy( texname, SideDefs[ sdlist->objnum].tex2, 8);
  1086.      sprintf( menustr[ 2], "Change Lower texture    (Current: %s)", texname);
  1087.      sprintf( menustr[ 3], "Change Texture X offset (Current: %d)", SideDefs[ sdlist->objnum].xoff);
  1088.      sprintf( menustr[ 4], "Change Texture Y offset (Current: %d)", SideDefs[ sdlist->objnum].yoff);
  1089.      sprintf( menustr[ 5], "Change Sector ref.      (Current: #%d)", SideDefs[ sdlist->objnum].sector);
  1090.      val = DisplayMenuArray( x0 + 42, y0 + 54, menustr[ 6], 6, NULL, menustr, dummy);
  1091.      for (n = 0; n < 7; n++)
  1092.         FreeMemory( menustr[ n]);
  1093.      switch (val)
  1094.      {
  1095.      case 1:
  1096.         strncpy( texname, SideDefs[ sdlist->objnum].tex3, 8);
  1097.         ObjectsNeeded( 0);
  1098.         ChooseWallTexture( x0 + 84, y0 + 88, "Choose a wall texture", NumWTexture, WTexture, texname);
  1099.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1100.         if (strlen(texname) > 0)
  1101.         {
  1102.            for (cur = sdlist; cur; cur = cur->next)
  1103.           if (cur->objnum >= 0)
  1104.              strncpy( SideDefs[ cur->objnum].tex3, texname, 8);
  1105.            MadeChanges = TRUE;
  1106.         }
  1107.         break;
  1108.      case 2:
  1109.         strncpy( texname, SideDefs[ sdlist->objnum].tex1, 8);
  1110.         ObjectsNeeded( 0);
  1111.         ChooseWallTexture( x0 + 84, y0 + 98, "Choose a wall texture", NumWTexture, WTexture, texname);
  1112.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1113.         if (strlen(texname) > 0)
  1114.         {
  1115.            for (cur = sdlist; cur; cur = cur->next)
  1116.           if (cur->objnum >= 0)
  1117.              strncpy( SideDefs[ cur->objnum].tex1, texname, 8);
  1118.            MadeChanges = TRUE;
  1119.         }
  1120.         break;
  1121.      case 3:
  1122.         strncpy( texname, SideDefs[ sdlist->objnum].tex2, 8);
  1123.         ObjectsNeeded( 0);
  1124.         ChooseWallTexture( x0 + 84, y0 + 108, "Choose a wall texture", NumWTexture, WTexture, texname);
  1125.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1126.         if (strlen(texname) > 0)
  1127.         {
  1128.            for (cur = sdlist; cur; cur = cur->next)
  1129.           if (cur->objnum >= 0)
  1130.              strncpy( SideDefs[ cur->objnum].tex2, texname, 8);
  1131.            MadeChanges = TRUE;
  1132.         }
  1133.         break;
  1134.      case 4:
  1135.         val = InputIntegerValue( x0 + 84, y0 + 118, -255, 255, SideDefs[ sdlist->objnum].xoff);
  1136.         if (val >= -255)
  1137.         {
  1138.            for (cur = sdlist; cur; cur = cur->next)
  1139.           if (cur->objnum >= 0)
  1140.              SideDefs[ cur->objnum].xoff = val;
  1141.            MadeChanges = TRUE;
  1142.         }
  1143.         break;
  1144.      case 5:
  1145.         val = InputIntegerValue( x0 + 84, y0 + 128, -255, 255, SideDefs[ sdlist->objnum].yoff);
  1146.         if (val >= -255)
  1147.         {
  1148.            for (cur = sdlist; cur; cur = cur->next)
  1149.           if (cur->objnum >= 0)
  1150.              SideDefs[ cur->objnum].yoff = val;
  1151.            MadeChanges = TRUE;
  1152.         }
  1153.         break;
  1154.      case 6:
  1155.         val = InputObjectXRef( x0 + 84, y0 + 138, OBJ_SECTORS, FALSE, SideDefs[ sdlist->objnum].sector);
  1156.         if (val >= 0)
  1157.         {
  1158.            for (cur = sdlist; cur; cur = cur->next)
  1159.           if (cur->objnum >= 0)
  1160.              SideDefs[ cur->objnum].sector = val;
  1161.            MadeChanges = TRUE;
  1162.         }
  1163.         break;
  1164.      }
  1165.      ForgetSelection( &sdlist);
  1166.      break;
  1167.  
  1168.       }
  1169.       break;
  1170.  
  1171.    case OBJ_SECTORS:
  1172.       for (n = 0; n < 8; n++)
  1173.      menustr[ n] = GetMemory( 60);
  1174.       sprintf( menustr[ 7], "Edit Sector #%d", obj->objnum);
  1175.       sprintf( menustr[ 0], "Change Floor height     (Current: %d)", Sectors[ obj->objnum].floorh);
  1176.       sprintf( menustr[ 1], "Change Ceiling height   (Current: %d)", Sectors[ obj->objnum].ceilh);
  1177.       texname[ 8] = '\0';
  1178.       strncpy( texname, Sectors[ obj->objnum].floort, 8);
  1179.       sprintf( menustr[ 2], "Change Floor texture    (Current: %s)", texname);
  1180.       strncpy( texname, Sectors[ obj->objnum].ceilt, 8);
  1181.       sprintf( menustr[ 3], "Change Ceiling texture  (Current: %s)", texname);
  1182.       sprintf( menustr[ 4], "Change Light level      (Current: %d)", Sectors[ obj->objnum].light);
  1183.       sprintf( menustr[ 5], "Change Type             (Current: %d)", Sectors[ obj->objnum].special);
  1184.       sprintf( menustr[ 6], "Change LineDef tag      (Current: %d)", Sectors[ obj->objnum].tag);
  1185.       val = DisplayMenuArray( x0, y0, menustr[ 7], 7, NULL, menustr, dummy);
  1186.       for (n = 0; n < 8; n++)
  1187.      FreeMemory( menustr[ n]);
  1188.       switch (val)
  1189.       {
  1190.       case 1:
  1191.      val = InputIntegerValue( x0 + 42, y0 + 34, -16384, 16383, Sectors[ obj->objnum].floorh);
  1192.      if (val >= -16384)
  1193.      {
  1194.         for (cur = obj; cur; cur = cur->next)
  1195.            Sectors[ cur->objnum].floorh = val;
  1196.         MadeChanges = TRUE;
  1197.      }
  1198.      break;
  1199.       case 2:
  1200.      val = InputIntegerValue( x0 + 42, y0 + 44, -16384, 16383, Sectors[ obj->objnum].ceilh);
  1201.      if (val >= -16384)
  1202.      {
  1203.         for (cur = obj; cur; cur = cur->next)
  1204.            Sectors[ cur->objnum].ceilh = val;
  1205.         MadeChanges = TRUE;
  1206.      }
  1207.      break;
  1208.       case 3:
  1209.      strncpy( texname, Sectors[ obj->objnum].floort, 8);
  1210.      ObjectsNeeded( 0);
  1211.      ChooseFloorTexture( x0 + 42, y0 + 54, "Choose a floor texture", NumFTexture, FTexture, texname);
  1212.      ObjectsNeeded( OBJ_SECTORS, 0);
  1213.      if (strlen(texname) > 0)
  1214.      {
  1215.         for (cur = obj; cur; cur = cur->next)
  1216.            strncpy( Sectors[ cur->objnum].floort, texname, 8);
  1217.         MadeChanges = TRUE;
  1218.      }
  1219.      break;
  1220.       case 4:
  1221.      strncpy( texname, Sectors[ obj->objnum].ceilt, 8);
  1222.      ObjectsNeeded( 0);
  1223.      ChooseFloorTexture( x0 + 42, y0 + 64, "Choose a ceiling texture", NumFTexture, FTexture, texname);
  1224.      ObjectsNeeded( OBJ_SECTORS, 0);
  1225.      if (strlen(texname) > 0)
  1226.      {
  1227.         for (cur = obj; cur; cur = cur->next)
  1228.            strncpy( Sectors[ cur->objnum].ceilt, texname, 8);
  1229.         MadeChanges = TRUE;
  1230.      }
  1231.      break;
  1232.       case 5:
  1233.      val = InputIntegerValue( x0 + 42, y0 + 74, 0, 255, Sectors[ obj->objnum].light);
  1234.      if (val >= 0)
  1235.      {
  1236.         for (cur = obj; cur; cur = cur->next)
  1237.            Sectors[ cur->objnum].light = val;
  1238.         MadeChanges = TRUE;
  1239.      }
  1240.      break;
  1241.       case 6:
  1242.      val = DisplayMenu( x0 + 42, y0 + 84, "Choose a special behaviour",
  1243.                 GetSectorTypeLongName( 0),
  1244.                 GetSectorTypeLongName( 1),
  1245.                 GetSectorTypeLongName( 2),
  1246.                 GetSectorTypeLongName( 3),
  1247.                 GetSectorTypeLongName( 4),
  1248.                 GetSectorTypeLongName( 5),
  1249.                 GetSectorTypeLongName( 7),
  1250.                 GetSectorTypeLongName( 8),
  1251.                 GetSectorTypeLongName( 9),
  1252.                 GetSectorTypeLongName( 10),
  1253.                 GetSectorTypeLongName( 11),
  1254.                 GetSectorTypeLongName( 12),
  1255.                 GetSectorTypeLongName( 13),
  1256.                 GetSectorTypeLongName( 14),
  1257.                 GetSectorTypeLongName( 16),
  1258.                 "(Enter a decimal value)",
  1259.                 NULL);
  1260.      switch (val)
  1261.      {
  1262.      case 1:
  1263.      case 2:
  1264.      case 3:
  1265.      case 4:
  1266.      case 5:
  1267.      case 6:
  1268.         for (cur = obj; cur; cur = cur->next)
  1269.            Sectors[ cur->objnum].special = val - 1;
  1270.         MadeChanges = TRUE;
  1271.         break;
  1272.      case 7:
  1273.      case 8:
  1274.      case 9:
  1275.      case 10:
  1276.      case 11:
  1277.      case 12:
  1278.      case 13:
  1279.      case 14:
  1280.         for (cur = obj; cur; cur = cur->next)
  1281.            Sectors[ cur->objnum].special = val;
  1282.         MadeChanges = TRUE;
  1283.         break;
  1284.      case 15:
  1285.         for (cur = obj; cur; cur = cur->next)
  1286.            Sectors[ cur->objnum].special = 16;
  1287.         MadeChanges = TRUE;
  1288.         break;
  1289.      case 16:
  1290.         val = InputIntegerValue( x0 + 84, y0 + 208, 0, 255, Sectors[ obj->objnum].special);
  1291.         if (val >= 0)
  1292.         {
  1293.            for (cur = obj; cur; cur = cur->next)
  1294.           Sectors[ cur->objnum].special = val;
  1295.            MadeChanges = TRUE;
  1296.         }
  1297.         break;
  1298.      }
  1299.      break;
  1300.       case 7:
  1301.      val = InputIntegerValue( x0 + 42, y0 + 94, 0, 999, Sectors[ obj->objnum].tag);
  1302.      if (val >= 0)
  1303.      {
  1304.         for (cur = obj; cur; cur = cur->next)
  1305.            Sectors[ cur->objnum].tag = val;
  1306.         MadeChanges = TRUE;
  1307.      }
  1308.      break;
  1309.       }
  1310.       break;
  1311.    }
  1312. }
  1313.  
  1314.  
  1315.  
  1316. /*
  1317.    Yuck!  Dirty piece of code...
  1318. */
  1319.  
  1320. Bool Input2Numbers( int x0, int y0, char *name1, char *name2, int v1max, int v2max, int *v1, int *v2)
  1321. {
  1322.    int  key;
  1323.    int  maxlen, first;
  1324.    Bool ok;
  1325.    char prompt[ 80];
  1326.  
  1327.    if (UseMouse)
  1328.       HideMousePointer();
  1329.    sprintf( prompt, "Give the %s and %s for the object:", name1, name2);
  1330.    maxlen = strlen( prompt);
  1331.    if (x0 < 0)
  1332.       x0 = (ScrMaxX - 25 - 8 * maxlen) / 2;
  1333.    if (y0 < 0)
  1334.       y0 = (ScrMaxY - 75) / 2;
  1335.    DrawScreenBox3D( x0, y0, x0 + 25 + 8 * maxlen, y0 + 75);
  1336.    DrawScreenText( x0 + 10, y0 + 26, name1);
  1337.    DrawScreenText( x0 + 180, y0 + 26, name2);
  1338.    DrawScreenText( x0 + 10, y0 + 58, "(0-%d)", v1max);
  1339.    DrawScreenText( x0 + 180, y0 + 58, "(0-%d)", v2max);
  1340.    SetColor( WHITE);
  1341.    DrawScreenText( x0 + 10, y0 + 8, prompt);
  1342.    first = TRUE;
  1343.    key = 0;
  1344.    for (;;)
  1345.    {
  1346.       ok = TRUE;
  1347.       DrawScreenBox3D( x0 + 10, y0 + 38, x0 + 71, y0 + 51);
  1348.       if (*v1 < 0 || *v1 > v1max)
  1349.       {
  1350.      SetColor( DARKGRAY);
  1351.      ok = FALSE;
  1352.       }
  1353.       DrawScreenText( x0 + 14, y0 + 41, "%d", *v1);
  1354.       DrawScreenBox3D( x0 + 180, y0 + 38, x0 + 241, y0 + 51);
  1355.       if (*v2 < 0 || *v2 > v2max)
  1356.       {
  1357.      SetColor( DARKGRAY);
  1358.      ok = FALSE;
  1359.       }
  1360.       DrawScreenText( x0 + 184, y0 + 41, "%d", *v2);
  1361.       if (first)
  1362.      key = InputInteger( x0 + 10, y0 + 38, v1, 0, v1max);
  1363.       else
  1364.      key = InputInteger( x0 + 180, y0 + 38, v2, 0, v2max);
  1365.       if ((key & 0xFF00) == 0x4B00 || (key & 0xFF00) == 0x4D00 || (key & 0x00FF) == 0x0009 || (key & 0xFF00) == 0x0F00)
  1366.      first = !first;
  1367.       else if ((key & 0x00FF) == 0x001B)
  1368.      break;
  1369.       else if ((key & 0x00FF) == 0x000D)
  1370.       {
  1371.      if (first)
  1372.         first = FALSE;
  1373.      else if (ok)
  1374.         break;
  1375.      else
  1376.         Beep();
  1377.       }
  1378.       else
  1379.      Beep();
  1380.    }
  1381.    if (UseMouse)
  1382.       ShowMousePointer();
  1383.    return ((key & 0x00FF) == 0x000D);
  1384. }
  1385.  
  1386.  
  1387.  
  1388. /*
  1389.    display number of objects, etc.
  1390. */
  1391.  
  1392. void Statistics( int x0, int y0)
  1393. {
  1394.    if (x0 < 0)
  1395.       x0 = (ScrMaxX - 270) / 2;
  1396.    if (y0 < 0)
  1397.       y0 = (ScrMaxY - 100) / 2;
  1398.    if (UseMouse)
  1399.       HideMousePointer();
  1400.    DrawScreenBox3D( x0, y0, x0 + 270, y0 + 100);
  1401.    SetColor( WHITE);
  1402.    DrawScreenText( x0 + 10, y0 + 5, "Statistics");
  1403.    if (Things == NULL)
  1404.       SetColor( DARKGRAY);
  1405.    else
  1406.       SetColor( BLACK);
  1407.    DrawScreenText( -1, y0 + 25, "Number of Things:   %4d (%lu K)",
  1408.            NumThings, ((unsigned long) NumThings * sizeof( struct Thing) + 512L) / 1024L);
  1409.    if (Vertexes == NULL)
  1410.       SetColor( DARKGRAY);
  1411.    else
  1412.       SetColor( BLACK);
  1413.    DrawScreenText( -1, -1, "Number of Vertices: %4d (%lu K)",
  1414.            NumVertexes, ((unsigned long) NumVertexes * sizeof( struct Vertex) + 512L) / 1024L);
  1415.    if (LineDefs == NULL)
  1416.       SetColor( DARKGRAY);
  1417.    else
  1418.       SetColor( BLACK);
  1419.    DrawScreenText( -1, -1, "Number of LineDefs: %4d (%lu K)",
  1420.            NumLineDefs, ((unsigned long) NumLineDefs * sizeof( struct LineDef) + 512L) / 1024L);
  1421.    if (SideDefs == NULL)
  1422.       SetColor( DARKGRAY);
  1423.    else
  1424.       SetColor( BLACK);
  1425.    DrawScreenText( -1, -1, "Number of SideDefs: %4d (%lu K)",
  1426.            NumSideDefs, ((unsigned long) NumSideDefs * sizeof( struct SideDef) + 512L) / 1024L);
  1427.    if (Sectors == NULL)
  1428.       SetColor( DARKGRAY);
  1429.    else
  1430.       SetColor( BLACK);
  1431.    DrawScreenText( -1, -1, "Number of Sectors:  %4d (%lu K)",
  1432.            NumSectors, ((unsigned long) NumSectors * sizeof( struct Sector) + 512L) / 1024L);
  1433.    SetColor( YELLOW);
  1434.    DrawScreenText( x0 + 10, y0 + 85, "Press any key to continue...");
  1435.    bioskey( 0);
  1436.    if (UseMouse)
  1437.       ShowMousePointer();
  1438. }
  1439.  
  1440.  
  1441.  
  1442. /*
  1443.    display a message while the user is waiting...
  1444. */
  1445.  
  1446. void CheckingObjects( int x0, int y0)
  1447. {
  1448.    if (UseMouse)
  1449.       HideMousePointer();
  1450.    if (x0 < 0)
  1451.      x0 = (ScrMaxX - 172) / 2;
  1452.    if (y0 < 0)
  1453.      y0 = (ScrMaxY - 30) / 2;
  1454.    DrawScreenBox3D( x0, y0, x0 + 172, y0 + 30);
  1455.    DrawScreenText( x0 + 10, y0 + 5, "Checking objects...");
  1456.    DrawScreenText( x0 + 10, y0 + 15, "   Please wait");
  1457.    if (UseMouse)
  1458.       ShowMousePointer();
  1459. }
  1460.  
  1461.  
  1462.  
  1463.  
  1464. /*
  1465.    display a message, then ask if the check should continue (prompt2 may be NULL)
  1466. */
  1467.  
  1468. Bool CheckFailed( int x0, int y0, char *prompt1, char *prompt2, Bool fatal)
  1469. {
  1470.    int key;
  1471.    int maxlen;
  1472.  
  1473.    if (UseMouse)
  1474.       HideMousePointer();
  1475.    if (fatal == TRUE)
  1476.       maxlen = 44;
  1477.    else
  1478.       maxlen = 27;
  1479.    if (strlen( prompt1) > maxlen)
  1480.       maxlen = strlen( prompt1);
  1481.    if (prompt2 != NULL && strlen( prompt2) > maxlen)
  1482.       maxlen = strlen( prompt2);
  1483.    if (x0 < 0)
  1484.       x0 = (ScrMaxX - 22 - 8 * maxlen) / 2;
  1485.    if (y0 < 0)
  1486.       y0 = (ScrMaxY - (prompt2 ? 73 : 63)) / 2;
  1487.    DrawScreenBox3D( x0, y0, x0 + 22 + 8 * maxlen, y0 + (prompt2 ? 73 : 63));
  1488.    SetColor( RED);
  1489.    DrawScreenText( x0 + 10, y0 + 8, "Verification failed:");
  1490.    Beep();
  1491.    SetColor( WHITE);
  1492.    DrawScreenText( x0 + 10, y0 + 18, prompt1);
  1493.    LogMessage( "\t%s\n", prompt1);
  1494.    if (prompt2 != NULL)
  1495.    {
  1496.       DrawScreenText( x0 + 10, y0 + 28, prompt2);
  1497.       LogMessage( "\t%s\n", prompt2);
  1498.    }
  1499.    if (fatal == TRUE)
  1500.    {
  1501.       DrawScreenText( x0 + 10, y0 + (prompt2 ? 38 : 28), "DOOM will crash if you play with this level.");
  1502.       SetColor( YELLOW);
  1503.       DrawScreenText( x0 + 10, y0 + (prompt2 ? 58 : 48), "Press any key to see the object");
  1504.       LogMessage( "\n");
  1505.    }
  1506.    else
  1507.    {
  1508.       SetColor( YELLOW);
  1509.       DrawScreenText( x0 + 10, y0 + (prompt2 ? 48 : 38), "Press Esc to see the object,");
  1510.       DrawScreenText( x0 + 10, y0 + (prompt2 ? 58 : 48), "or any other key to continue");
  1511.    }
  1512.    key = bioskey( 0);
  1513.    if ((key & 0x00FF) != 0x001B)
  1514.    {
  1515.       DrawScreenBox3D( x0, y0, x0 + 22 + 8 * maxlen, y0 + (prompt2 ? 73 : 63));
  1516.       DrawScreenText( x0 + 10 + 4 * (maxlen - 26), y0 + 28, "Verifying other objects...");
  1517.    }
  1518.    if (UseMouse)
  1519.       ShowMousePointer();
  1520.    return ((key & 0x00FF) == 0x001B);
  1521. }
  1522.  
  1523.  
  1524.  
  1525.  
  1526. /*
  1527.    check if all sectors are closed
  1528. */
  1529.  
  1530. void CheckSectors( void) /* SWAP! */
  1531. {
  1532.    int        s, n, sd;
  1533.    char huge *ends;
  1534.    char       msg1[ 80], msg2[80];
  1535.  
  1536.    CheckingObjects( -1, -1);
  1537.    LogMessage( "\nVerifying Sectors...\n");
  1538.    ObjectsNeeded( OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
  1539.    ends = GetFarMemory( NumVertexes * sizeof( char));
  1540.    for (s = 0; s < NumSectors; s++)
  1541.    {
  1542.       /* clear the "ends" array */
  1543.       for (n = 0; n < NumVertexes; n++)
  1544.      ends[ n] = 0;
  1545.       /* for each SideDef bound to the Sector, store a "1" in the "ends" */
  1546.       /* array for its starting Vertex, and a "2" for its ending Vertex  */
  1547.       for (n = 0; n < NumLineDefs; n++)
  1548.       {
  1549.      sd = LineDefs[ n].sidedef1;
  1550.      if (sd >= 0 && SideDefs[ sd].sector == s)
  1551.      {
  1552.         ends[ LineDefs[ n].start] |= 1;
  1553.         ends[ LineDefs[ n].end] |= 2;
  1554.      }
  1555.      sd = LineDefs[ n].sidedef2;
  1556.      if (sd >= 0 && SideDefs[ sd].sector == s)
  1557.      {
  1558.         ends[ LineDefs[ n].end] |= 1;
  1559.         ends[ LineDefs[ n].start] |= 2;
  1560.      }
  1561.       }
  1562.       /* every entry in the "ends" array should be "0" or "3" */
  1563.       for (n = 0; n < NumVertexes; n++)
  1564.       {
  1565.      if (ends[ n] == 1)
  1566.      {
  1567.         sprintf( msg1, "Sector #%d is not closed!", s);
  1568.         sprintf( msg2, "There is no SideDef ending at Vertex #%d", n);
  1569.         if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1570.         {
  1571.            GoToObject( OBJ_VERTEXES, n);
  1572.            return;
  1573.         }
  1574.      }
  1575.      if (ends[ n] == 2)
  1576.      {
  1577.         sprintf( msg1, "Sector #%d is not closed!", s);
  1578.         sprintf( msg2, "There is no SideDef starting at Vertex #%d", n);
  1579.         if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1580.         {
  1581.            GoToObject( OBJ_VERTEXES, n);
  1582.            return;
  1583.         }
  1584.      }
  1585.       }
  1586.    }
  1587.    FreeFarMemory( ends);
  1588.  
  1589.    /*
  1590.       Note from RQ:
  1591.      This is a very simple idea, but it works!  The first test (above)
  1592.      checks that all Sectors are closed.  But if a closed set of LineDefs
  1593.      is moved out of a Sector and has all its "external" SideDefs pointing
  1594.      to that Sector instead of the new one, then we need a second test.
  1595.      That's why I check if the SideDefs facing each other are bound to
  1596.      the same Sector.
  1597.  
  1598.       Other note from RQ:
  1599.      Nowadays, what makes the power of a good editor is its automatic tests.
  1600.      So, if you are writing another Doom editor, you will probably want
  1601.      to do the same kind of tests in your program.  Fine, but if you use
  1602.      these ideas, don't forget to credit DEU...  Just a reminder... :-)
  1603.    */
  1604.  
  1605.    /* now check if all SideDefs are facing a SideDef with the same Sector number */
  1606.    for (n = 0; n < NumLineDefs; n++)
  1607.    {
  1608.       ObjectsNeeded( OBJ_LINEDEFS, 0);
  1609.       sd = LineDefs[ n].sidedef1;
  1610.       if (sd >= 0)
  1611.       {
  1612.      s = GetOppositeSector( n, TRUE);
  1613.      ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1614.      if (s < 0 || SideDefs[ sd].sector != s)
  1615.      {
  1616.         if (s < 0)
  1617.         {
  1618.            sprintf( msg1, "Sector #%d is not closed!", SideDefs[ sd].sector);
  1619.            sprintf( msg2, "Check LineDef #%d (first SideDef: #%d)", n, sd);
  1620.         }
  1621.         else
  1622.         {
  1623.            sprintf( msg1, "Sectors #%d and #%d are not closed!", SideDefs[ sd].sector, s);
  1624.            sprintf( msg2, "Check LineDef #%d (first SideDef: #%d) and the one facing it", n, sd);
  1625.         }
  1626.         if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1627.         {
  1628.            GoToObject( OBJ_LINEDEFS, n);
  1629.            return;
  1630.         }
  1631.      }
  1632.       }
  1633.       ObjectsNeeded( OBJ_LINEDEFS, 0);
  1634.       sd = LineDefs[ n].sidedef2;
  1635.       if (sd >= 0)
  1636.       {
  1637.      s = GetOppositeSector( n, FALSE);
  1638.      ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1639.      if (s < 0 || SideDefs[ sd].sector != s)
  1640.      {
  1641.         if (s < 0)
  1642.         {
  1643.            sprintf( msg1, "Sector #%d is not closed!", SideDefs[ sd].sector);
  1644.            sprintf( msg2, "Check LineDef #%d (second SideDef: #%d)", n, sd);
  1645.         }
  1646.         else
  1647.         {
  1648.            sprintf( msg1, "Sectors #%d and #%d are not closed!", SideDefs[ sd].sector, s);
  1649.            sprintf( msg2, "Check LineDef #%d (second SideDef: #%d) and the one facing it", n, sd);
  1650.         }
  1651.         if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1652.         {
  1653.            GoToObject( OBJ_LINEDEFS, n);
  1654.            return;
  1655.         }
  1656.      }
  1657.       }
  1658.    }
  1659. }
  1660.  
  1661.  
  1662.  
  1663. /*
  1664.    check cross-references and delete unused objects
  1665. */
  1666.  
  1667. void CheckCrossReferences( void) /* SWAP! */
  1668. {
  1669.    char   msg[ 80];
  1670.    int    n, m;
  1671.    SelPtr cur;
  1672.  
  1673.    CheckingObjects( -1, -1);
  1674.    LogMessage( "\nVerifying cross-references...\n");
  1675.    ObjectsNeeded( OBJ_LINEDEFS, 0);
  1676.    for (n = 0; n < NumLineDefs; n++)
  1677.    {
  1678.       /* check for missing first SideDefs */
  1679.       if (LineDefs[ n].sidedef1 < 0)
  1680.       {
  1681.      sprintf( msg, "ERROR: LineDef #%d has no first SideDef!", n);
  1682.      CheckFailed( -1, -1, msg, NULL, TRUE);
  1683.      GoToObject( OBJ_LINEDEFS, n);
  1684.      return;
  1685.       }
  1686.       /* check for SideDefs used twice in the same LineDef */
  1687.       if (LineDefs[ n].sidedef1 == LineDefs[ n].sidedef2)
  1688.       {
  1689.      sprintf( msg, "ERROR: LineDef #%d uses the same SideDef twice (#%d)", n, LineDefs[ n].sidedef1);
  1690.      CheckFailed( -1, -1, msg, NULL, TRUE);
  1691.      GoToObject( OBJ_LINEDEFS, n);
  1692.      return;
  1693.       }
  1694.       /* check for Vertices used twice in the same LineDef */
  1695.       if (LineDefs[ n].start == LineDefs[ n].end)
  1696.       {
  1697.      sprintf( msg, "ERROR: LineDef #%d uses the same Vertex twice (#%d)", n, LineDefs[ n].start);
  1698.      CheckFailed( -1, -1, msg, NULL, TRUE);
  1699.      GoToObject( OBJ_LINEDEFS, n);
  1700.      return;
  1701.       }
  1702.    }
  1703.  
  1704.    /* check if there aren't two LineDefs between the same Vertices */
  1705.    cur = NULL;
  1706.    for (n = NumLineDefs - 1; n >= 1; n--)
  1707.    {
  1708.       for (m = n - 1; m >= 0; m--)
  1709.      if ((LineDefs[ n].start == LineDefs[ m].start && LineDefs[ n].end == LineDefs[ m].end)
  1710.       || (LineDefs[ n].start == LineDefs[ m].end && LineDefs[ n].end == LineDefs[ m].start))
  1711.      {
  1712.         SelectObject( &cur, n);
  1713.         break;
  1714.      }
  1715.    }
  1716.    if (cur && (Expert || Confirm(-1, -1, "There are multiple LineDefs between the same Vertices", "Do you want to delete the redundant LineDefs?")))
  1717.       DeleteObjects( OBJ_LINEDEFS, &cur);
  1718.    else
  1719.       ForgetSelection( &cur);
  1720.  
  1721.    CheckingObjects( -1, -1);
  1722.    /* check for invalid flags in the LineDefs */
  1723.    for (n = 0; n < NumLineDefs; n++)
  1724.       if ((LineDefs[ n].flags & 0x01) == 0 && LineDefs[ n].sidedef2 < 0)
  1725.      SelectObject( &cur, n);
  1726.    if (cur && (Expert || Confirm(-1, -1, "Some LineDefs have only one side but their Im bit is not set", "Do you want to set the 'Impassible' flag?")))
  1727.    {
  1728.       while (cur)
  1729.       {
  1730.      LineDefs[ cur->objnum].flags |= 0x01;
  1731.      UnSelectObject( &cur, cur->objnum);
  1732.       }
  1733.    }
  1734.    else
  1735.       ForgetSelection( &cur);
  1736.  
  1737.    CheckingObjects( -1, -1);
  1738.    for (n = 0; n < NumLineDefs; n++)
  1739.       if ((LineDefs[ n].flags & 0x04) != 0 && LineDefs[ n].sidedef2 < 0)
  1740.      SelectObject( &cur, n);
  1741.    if (cur && (Expert || Confirm(-1, -1, "Some LineDefs have only one side but their 2S bit is set", "Do you want to clear the 'two-sided' flag?")))
  1742.    {
  1743.       while (cur)
  1744.       {
  1745.      LineDefs[ cur->objnum].flags &= ~0x04;
  1746.      UnSelectObject( &cur, cur->objnum);
  1747.       }
  1748.    }
  1749.    else
  1750.       ForgetSelection( &cur);
  1751.  
  1752.    CheckingObjects( -1, -1);
  1753.    for (n = 0; n < NumLineDefs; n++)
  1754.       if ((LineDefs[ n].flags & 0x04) == 0 && LineDefs[ n].sidedef2 >= 0)
  1755.      SelectObject( &cur, n);
  1756.    if (cur && (Expert || Confirm(-1, -1, "Some LineDefs have two sides but their 2S bit is not set", "Do you want to set the 'two-sided' flag?")))
  1757.    {
  1758.       while (cur)
  1759.       {
  1760.      LineDefs[ cur->objnum].flags |= 0x04;
  1761.      UnSelectObject( &cur, cur->objnum);
  1762.       }
  1763.    }
  1764.    else
  1765.       ForgetSelection( &cur);
  1766.  
  1767.    CheckingObjects( -1, -1);
  1768.    /* select all Vertices */
  1769.    for (n = 0; n < NumVertexes; n++)
  1770.       SelectObject( &cur, n);
  1771.    /* unselect Vertices used in a LineDef */
  1772.    for (n = 0; n < NumLineDefs; n++)
  1773.    {
  1774.       m = LineDefs[ n].start;
  1775.       if (cur && m >= 0)
  1776.      UnSelectObject( &cur, m);
  1777.       m = LineDefs[ n].end;
  1778.       if (cur && m >= 0)
  1779.      UnSelectObject( &cur, m);
  1780.       continue;
  1781.    }
  1782.    /* check if there are any Vertices left */
  1783.    if (cur && (Expert || Confirm(-1, -1, "Some Vertices are not bound to any LineDef", "Do you want to delete these unused Vertices?")))
  1784.    {
  1785.       DeleteObjects( OBJ_VERTEXES, &cur);
  1786.       ObjectsNeeded( OBJ_LINEDEFS, 0);
  1787.    }
  1788.    else
  1789.       ForgetSelection( &cur);
  1790.  
  1791.    CheckingObjects( -1, -1);
  1792.    /* select all SideDefs */
  1793.    for (n = 0; n < NumSideDefs; n++)
  1794.       SelectObject( &cur, n);
  1795.    /* unselect SideDefs bound to a LineDef */
  1796.    for (n = 0; n < NumLineDefs; n++)
  1797.    {
  1798.       m = LineDefs[ n].sidedef1;
  1799.       if (cur && m >= 0)
  1800.      UnSelectObject( &cur, m);
  1801.       m = LineDefs[ n].sidedef2;
  1802.       if (cur && m >= 0)
  1803.      UnSelectObject( &cur, m);
  1804.       continue;
  1805.    }
  1806.    /* check if there are any SideDefs left */
  1807.    if (cur && (Expert || Confirm(-1, -1, "Some SideDefs are not bound to any LineDef", "Do you want to delete these unused SideDefs?")))
  1808.       DeleteObjects( OBJ_SIDEDEFS, &cur);
  1809.    else
  1810.       ForgetSelection( &cur);
  1811.  
  1812.    CheckingObjects( -1, -1);
  1813.    /* select all Sectors */
  1814.    for (n = 0; n < NumSectors; n++)
  1815.       SelectObject( &cur, n);
  1816.    /* unselect Sectors bound to a SideDef */
  1817.    for (n = 0; n < NumLineDefs; n++)
  1818.    {
  1819.       ObjectsNeeded( OBJ_LINEDEFS, 0);
  1820.       m = LineDefs[ n].sidedef1;
  1821.       ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1822.       if (cur && m >= 0 && SideDefs[ m].sector >= 0)
  1823.      UnSelectObject( &cur, SideDefs[ m].sector);
  1824.       ObjectsNeeded( OBJ_LINEDEFS, 0);
  1825.       m = LineDefs[ n].sidedef2;
  1826.       ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1827.       if (cur && m >= 0 && SideDefs[ m].sector >= 0)
  1828.      UnSelectObject( &cur, SideDefs[ m].sector);
  1829.       continue;
  1830.    }
  1831.    /* check if there are any Sectors left */
  1832.    if (cur && (Expert || Confirm(-1, -1, "Some Sectors are not bound to any SideDef", "Do you want to delete these unused Sectors?")))
  1833.       DeleteObjects( OBJ_SECTORS, &cur);
  1834.    else
  1835.       ForgetSelection( &cur);
  1836. }
  1837.  
  1838.  
  1839.  
  1840. /*
  1841.    check for missing textures
  1842. */
  1843.  
  1844. void CheckTextures( void) /* SWAP! */
  1845. {
  1846.    int  n;
  1847.    int  sd1, sd2;
  1848.    int  s1, s2;
  1849.    char msg1[ 80], msg2[ 80];
  1850.  
  1851.    CheckingObjects( -1, -1);
  1852.    LogMessage( "\nVerifying textures...\n");
  1853.    ObjectsNeeded( OBJ_SECTORS, 0);
  1854.    for (n = 0; n < NumSectors; n++)
  1855.    {
  1856.       if (Sectors[ n].ceilt[ 0] == '-' && Sectors[ n].ceilt == '\0')
  1857.       {
  1858.      sprintf( msg1, "Error: Sector #%d has no ceiling texture", n);
  1859.      sprintf( msg2, "You probaly used a brain-damaged editor to do that...");
  1860.      CheckFailed( -1, -1, msg1, msg2, TRUE);
  1861.      GoToObject( OBJ_SECTORS, n);
  1862.      return;
  1863.       }
  1864.       if (Sectors[ n].floort[ 0] == '-' && Sectors[ n].floort == '\0')
  1865.       {
  1866.      sprintf( msg1, "Error: Sector #%d has no floor texture", n);
  1867.      sprintf( msg2, "You probaly used a brain-damaged editor to do that...");
  1868.      CheckFailed( -1, -1, msg1, msg2, TRUE);
  1869.      GoToObject( OBJ_SECTORS, n);
  1870.      return;
  1871.       }
  1872.       if (Sectors[ n].ceilh < Sectors[ n].floorh)
  1873.       {
  1874.      sprintf( msg1, "Error: Sector #%d has its ceiling lower than its floor", n);
  1875.      sprintf( msg2, "The textures will never be displayed if you cannot go there");
  1876.      CheckFailed( -1, -1, msg1, msg2, TRUE);
  1877.      GoToObject( OBJ_SECTORS, n);
  1878.      return;
  1879.       }
  1880.       if (Sectors[ n].ceilh - Sectors[ n].floorh > 1023)
  1881.       {
  1882.      sprintf( msg1, "Error: Sector #%d has its ceiling too high", n);
  1883.      sprintf( msg2, "The maximum difference allowed is 1023 (ceiling - floor)");
  1884.      CheckFailed( -1, -1, msg1, msg2, TRUE);
  1885.      GoToObject( OBJ_SECTORS, n);
  1886.      return;
  1887.       }
  1888.    }
  1889.    for (n = 0; n < NumLineDefs; n++)
  1890.    {
  1891.       ObjectsNeeded( OBJ_LINEDEFS, 0);
  1892.       sd1 = LineDefs[ n].sidedef1;
  1893.       sd2 = LineDefs[ n].sidedef2;
  1894.       ObjectsNeeded( OBJ_SIDEDEFS, OBJ_SECTORS, 0);
  1895.       if (sd1 >= 0)
  1896.      s1 = SideDefs[ sd1].sector;
  1897.       else
  1898.      s1 = -1;
  1899.       if (sd2 >= 0)
  1900.      s2 = SideDefs[ sd2].sector;
  1901.       else
  1902.      s2 = -1;
  1903.       if (s1 >= 0 && s2 < 0)
  1904.       {
  1905.      if (SideDefs[ sd1].tex3[ 0] == '-' && SideDefs[ sd1].tex3[ 1] == '\0')
  1906.      {
  1907.         sprintf( msg1, "Error in one-sided Linedef #%d: SideDef #%d has no normal texture", n, sd1);
  1908.         sprintf( msg2, "Do you want to set the texture to \"%s\" and continue?", DefaultWallTexture);
  1909.         if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1910.         {
  1911.            GoToObject( OBJ_LINEDEFS, n);
  1912.            return;
  1913.         }
  1914.         strncpy( SideDefs[ sd1].tex3, DefaultWallTexture, 8);
  1915.         CheckingObjects( -1, -1);
  1916.      }
  1917.       }
  1918.       if (s1 >= 0 && s2 >= 0 && Sectors[ s1].ceilh > Sectors[ s2].ceilh)
  1919.       {
  1920.      if (SideDefs[ sd1].tex1[ 0] == '-' && SideDefs[ sd1].tex1[ 1] == '\0'
  1921.          && (strncmp( Sectors[ s1].ceilt, "F_SKY1", 8) || strncmp( Sectors[ s2].ceilt, "F_SKY1", 8)))
  1922.      {
  1923.         sprintf( msg1, "Error in first SideDef of Linedef #%d: SideDef #%d has no upper texture", n, sd1);
  1924.         sprintf( msg2, "Do you want to set the texture to \"%s\" and continue?", DefaultUpperTexture);
  1925.         if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1926.         {
  1927.            GoToObject( OBJ_LINEDEFS, n);
  1928.            return;
  1929.         }
  1930.         strncpy( SideDefs[ sd1].tex1, DefaultUpperTexture, 8);
  1931.         CheckingObjects( -1, -1);
  1932.      }
  1933.       }
  1934.       if (s1 >= 0 && s2 >= 0 && Sectors[ s1].floorh < Sectors[ s2].floorh)
  1935.       {
  1936.      if (SideDefs[ sd1].tex2[ 0] == '-' && SideDefs[ sd1].tex2[ 1] == '\0')
  1937.      {
  1938.         sprintf( msg1, "Error in first SideDef of Linedef #%d: SideDef #%d has no lower texture", n, sd1);
  1939.         sprintf( msg2, "Do you want to set the texture to \"%s\" and continue?", DefaultLowerTexture);
  1940.         if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1941.         {
  1942.            GoToObject( OBJ_LINEDEFS, n);
  1943.            return;
  1944.         }
  1945.         strncpy( SideDefs[ sd1].tex2, DefaultLowerTexture, 8);
  1946.         CheckingObjects( -1, -1);
  1947.      }
  1948.       }
  1949.       if (s1 >= 0 && s2 >= 0 && Sectors[ s2].ceilh > Sectors[ s1].ceilh)
  1950.       {
  1951.      if (SideDefs[ sd2].tex1[ 0] == '-' && SideDefs[ sd2].tex1[ 1] == '\0'
  1952.          && (strncmp( Sectors[ s1].ceilt, "F_SKY1", 8) || strncmp( Sectors[ s2].ceilt, "F_SKY1", 8)))
  1953.      {
  1954.         sprintf( msg1, "Error in second SideDef of Linedef #%d: SideDef #%d has no upper texture", n, sd2);
  1955.         sprintf( msg2, "Do you want to set the texture to \"%s\" and continue?", DefaultUpperTexture);
  1956.         if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1957.         {
  1958.            GoToObject( OBJ_LINEDEFS, n);
  1959.            return;
  1960.         }
  1961.         strncpy( SideDefs[ sd2].tex1, DefaultUpperTexture, 8);
  1962.         CheckingObjects( -1, -1);
  1963.      }
  1964.       }
  1965.       if (s1 >= 0 && s2 >= 0 && Sectors[ s2].floorh < Sectors[ s1].floorh)
  1966.       {
  1967.      if (SideDefs[ sd2].tex2[ 0] == '-' && SideDefs[ sd2].tex2[ 1] == '\0')
  1968.      {
  1969.         sprintf( msg1, "Error in second SideDef of Linedef #%d: SideDef #%d has no lower texture", n, sd2);
  1970.         sprintf( msg2, "Do you want to set the texture to \"%s\" and continue?", DefaultLowerTexture);
  1971.         if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  1972.         {
  1973.            GoToObject( OBJ_LINEDEFS, n);
  1974.            return;
  1975.         }
  1976.         strncpy( SideDefs[ sd2].tex2, DefaultLowerTexture, 8);
  1977.         CheckingObjects( -1, -1);
  1978.      }
  1979.       }
  1980.    }
  1981. }
  1982.  
  1983.  
  1984.  
  1985. /*
  1986.    check if a texture name matches one of the elements of a list
  1987. */
  1988.  
  1989. Bool IsTextureNameInList( char *name, char **list, int numelems)
  1990. {
  1991.    int n;
  1992.  
  1993.    for (n = 0; n < numelems; n++)
  1994.       if (! strnicmp( name, list[ n], 8))
  1995.      return TRUE;
  1996.    return FALSE;
  1997. }
  1998.  
  1999.  
  2000.  
  2001. /*
  2002.    check for invalid texture names
  2003. */
  2004.  
  2005. void CheckTextureNames( void) /* SWAP! */
  2006. {
  2007.    int  n;
  2008.    char msg1[ 80], msg2[ 80];
  2009.  
  2010.    LogMessage( "\nVerifying texture names...\n");
  2011.    if (FindMasterDir( MasterDir, "F2_START") == NULL)
  2012.       NumThings--;
  2013.    ObjectsNeeded( OBJ_SECTORS, 0);
  2014.    for (n = 0; n < NumSectors; n++)
  2015.    {
  2016.       if (! IsTextureNameInList( Sectors[ n].ceilt, FTexture, NumFTexture))
  2017.       {
  2018.      sprintf( msg1, "Invalid ceiling texture in Sector #%d", n);
  2019.      sprintf( msg2, "The name \"%s\" is not a floor/ceiling texture", Sectors[ n].ceilt);
  2020.      if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  2021.      {
  2022.         GoToObject( OBJ_SECTORS, n);
  2023.         return;
  2024.      }
  2025.      CheckingObjects( -1, -1);
  2026.       }
  2027.       if (! IsTextureNameInList( Sectors[ n].floort, FTexture, NumFTexture))
  2028.       {
  2029.      sprintf( msg1, "Invalid floor texture in Sector #%d", n);
  2030.      sprintf( msg2, "The name \"%s\" is not a floor/ceiling texture", Sectors[ n].floort);
  2031.      if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  2032.      {
  2033.         GoToObject( OBJ_SECTORS, n);
  2034.         return;
  2035.      }
  2036.      CheckingObjects( -1, -1);
  2037.       }
  2038.    }
  2039.    ObjectsNeeded( OBJ_SIDEDEFS, 0);
  2040.    for (n = 0; n < NumSideDefs; n++)
  2041.    {
  2042.       if (! IsTextureNameInList( SideDefs[ n].tex1, WTexture, NumWTexture))
  2043.       {
  2044.      sprintf( msg1, "Invalid upper texture in SideDef #%d", n);
  2045.      sprintf( msg2, "The name \"%s\" is not a wall texture", SideDefs[ n].tex1);
  2046.      if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  2047.      {
  2048.         GoToObject( OBJ_SIDEDEFS, n);
  2049.         return;
  2050.      }
  2051.      CheckingObjects( -1, -1);
  2052.       }
  2053.       if (! IsTextureNameInList( SideDefs[ n].tex2, WTexture, NumWTexture))
  2054.       {
  2055.      sprintf( msg1, "Invalid lower texture in SideDef #%d", n);
  2056.      sprintf( msg2, "The name \"%s\" is not a wall texture", SideDefs[ n].tex2);
  2057.      if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  2058.      {
  2059.         GoToObject( OBJ_SIDEDEFS, n);
  2060.         return;
  2061.      }
  2062.      CheckingObjects( -1, -1);
  2063.       }
  2064.       if (! IsTextureNameInList( SideDefs[ n].tex3, WTexture, NumWTexture))
  2065.       {
  2066.      sprintf( msg1, "Invalid normal texture in SideDef #%d", n);
  2067.      sprintf( msg2, "The name \"%s\" is not a wall texture", SideDefs[ n].tex3);
  2068.      if (CheckFailed( -1, -1, msg1, msg2, FALSE))
  2069.      {
  2070.         GoToObject( OBJ_SIDEDEFS, n);
  2071.         return;
  2072.      }
  2073.      CheckingObjects( -1, -1);
  2074.       }
  2075.    }
  2076. }
  2077.  
  2078.  
  2079.  
  2080. /*
  2081.    check the level consistency
  2082. */
  2083.  
  2084. void CheckLevel( int x0, int y0) /* SWAP! */
  2085. {
  2086.    char *line5 = NULL;
  2087.  
  2088.    if (Registered)
  2089.    {
  2090.       if (FindMasterDir( MasterDir, "TEXTURE2") == NULL)
  2091.      NumVertexes--;
  2092.       else
  2093.      line5 = "Check texture names";
  2094.    }
  2095.    switch (DisplayMenu( x0, y0, ((x0 == -1) ? "Check level consistency" : NULL),
  2096.             "Number of objects",
  2097.             "Check if all Sectors are closed",
  2098.             "Check all cross-references",
  2099.             "Check for missing textures",
  2100.             line5,
  2101.             NULL))
  2102.    {
  2103.    case 1:
  2104.       Statistics( -1, -1);
  2105.       break;
  2106.    case 2:
  2107.       CheckSectors();
  2108.       break;
  2109.    case 3:
  2110.       CheckCrossReferences();
  2111.       break;
  2112.    case 4:
  2113.       CheckTextures();
  2114.       break;
  2115.    case 5:
  2116.       CheckTextureNames();
  2117.       break;
  2118.    }
  2119. }
  2120.  
  2121.  
  2122.  
  2123. /*
  2124.    check for players starting points
  2125. */
  2126.  
  2127. Bool CheckStartingPos() /* SWAP! */
  2128. {
  2129.    char msg1[ 80], msg2[80];
  2130.    Bool p1 = FALSE;
  2131.    Bool p2 = FALSE;
  2132.    Bool p3 = FALSE;
  2133.    Bool p4 = FALSE;
  2134.    int  dm = 0;
  2135.    int  t;
  2136.  
  2137.    ObjectsNeeded( OBJ_THINGS, 0);
  2138.    for (t = 0; t < NumThings; t++)
  2139.    {
  2140.       if (Things[ t].type == THING_PLAYER1)
  2141.      p1 = TRUE;
  2142.       if (Things[ t].type == THING_PLAYER2)
  2143.      p2 = TRUE;
  2144.       if (Things[ t].type == THING_PLAYER3)
  2145.      p3 = TRUE;
  2146.       if (Things[ t].type == THING_PLAYER4)
  2147.      p4 = TRUE;
  2148.       if (Things[ t].type == THING_DEATHMATCH)
  2149.      dm++;
  2150.    }
  2151.    if (p1 == FALSE)
  2152.    {
  2153.       Beep();
  2154.       sprintf( msg1, "Warning: there is no player 1 starting point!  DOOM will crash if");
  2155.       sprintf( msg2, "you play with this level.  Do you really want to save it?");
  2156.       return Confirm( -1, -1, msg1, msg2);
  2157.    }
  2158.    if (Expert)
  2159.       return TRUE;
  2160.    if (p2 == FALSE || p3 == FALSE || p4 == FALSE)
  2161.    {
  2162.       if (p4 == FALSE)
  2163.     t = 4;
  2164.       if (p3 == FALSE)
  2165.     t = 3;
  2166.       if (p2 == FALSE)
  2167.     t = 2;
  2168.       sprintf( msg1, "Warning: there is no player %d starting point.  You will not be able to", t);
  2169.       sprintf( msg2, "use this level for multi-player games.  Press Y to return to the editor.");
  2170.       return !Confirm( -1, -1, msg1, msg2);
  2171.    }
  2172.    if (dm < 4)
  2173.    {
  2174.       if (dm == 0)
  2175.      sprintf( msg1, "Warning: there are no DeathMatch starting points.  You need at least four");
  2176.       else if (dm == 1)
  2177.      sprintf( msg1, "Warning: there is only one DeathMatch starting point.  You need at least four");
  2178.       else
  2179.      sprintf( msg1, "Warning: there are only %d DeathMatch starting points.  You need at least four", dm);
  2180.       sprintf( msg2, "starting points to play DeathMatch games.  Press Y to return to the editor.");
  2181.       return !Confirm( -1, -1, msg1, msg2);
  2182.    }
  2183.    return TRUE;
  2184. }
  2185.  
  2186.  
  2187.  
  2188. /*
  2189.    insert a standard object at given position
  2190. */
  2191.  
  2192. void InsertStandardObject( int x0, int y0, int xpos, int ypos) /* SWAP! */
  2193. {
  2194.    int sector;
  2195.    int choice, n;
  2196.    int a, b;
  2197.  
  2198.    /* show where the object will be inserted */
  2199.    if (UseMouse)
  2200.       HideMousePointer();
  2201.    DrawPointer( TRUE);
  2202.    if (UseMouse)
  2203.       ShowMousePointer();
  2204.    /* are we inside a Sector? */
  2205.    sector = GetCurObject( OBJ_SECTORS, xpos, ypos, xpos, ypos);
  2206.    if (sector >= 0)
  2207.       choice = DisplayMenu( x0, y0, ((x0 == -1) ? "Insert a pre-defined object (inside a Sector)" : NULL),
  2208.                 "Rectangle",
  2209.                 "Polygon (N sides)",
  2210.                 "Stairs",
  2211.                 "Hidden stairs",
  2212.                 NULL);
  2213.    else
  2214.       choice = DisplayMenu( x0, y0, ((x0 == -1) ? "Insert a pre-defined object (outside)" : NULL),
  2215.                 "Rectangle",
  2216.                 "Polygon (N sides)",
  2217.                 NULL);
  2218.    /* !!!! Should also check for overlapping objects (sectors) !!!! */
  2219.    switch (choice)
  2220.    {
  2221.    case 1:
  2222.       a = 256;
  2223.       b = 128;
  2224.       if (Input2Numbers( -1, -1, "Width", "Height", 2000, 2000, &a, &b))
  2225.       {
  2226.      if (a < 8)
  2227.         a = 8;
  2228.      if (b < 8)
  2229.         b = 8;
  2230.      xpos = xpos - a / 2;
  2231.      ypos = ypos - b / 2;
  2232.      InsertObject( OBJ_VERTEXES, -1, xpos, ypos);
  2233.      InsertObject( OBJ_VERTEXES, -1, xpos + a, ypos);
  2234.      InsertObject( OBJ_VERTEXES, -1, xpos + a, ypos + b);
  2235.      InsertObject( OBJ_VERTEXES, -1, xpos, ypos + b);
  2236.      if (sector < 0)
  2237.         InsertObject( OBJ_SECTORS, -1, 0, 0);
  2238.      for (n = 0; n < 4; n++)
  2239.      {
  2240.         InsertObject( OBJ_LINEDEFS, -1, 0, 0);
  2241.         LineDefs[ NumLineDefs - 1].sidedef1 = NumSideDefs;
  2242.         InsertObject( OBJ_SIDEDEFS, -1, 0, 0);
  2243.         if (sector >= 0)
  2244.            SideDefs[ NumSideDefs - 1].sector = sector;
  2245.      }
  2246.      ObjectsNeeded( OBJ_LINEDEFS, 0);
  2247.      if (sector >= 0)
  2248.      {
  2249.         LineDefs[ NumLineDefs - 4].start = NumVertexes - 4;
  2250.         LineDefs[ NumLineDefs - 4].end = NumVertexes - 3;
  2251.         LineDefs[ NumLineDefs - 3].start = NumVertexes - 3;
  2252.         LineDefs[ NumLineDefs - 3].end = NumVertexes - 2;
  2253.         LineDefs[ NumLineDefs - 2].start = NumVertexes - 2;
  2254.         LineDefs[ NumLineDefs - 2].end = NumVertexes - 1;
  2255.         LineDefs[ NumLineDefs - 1].start = NumVertexes - 1;
  2256.         LineDefs[ NumLineDefs - 1].end = NumVertexes - 4;
  2257.      }
  2258.      else
  2259.      {
  2260.         LineDefs[ NumLineDefs - 4].start = NumVertexes - 1;
  2261.         LineDefs[ NumLineDefs - 4].end = NumVertexes - 2;
  2262.         LineDefs[ NumLineDefs - 3].start = NumVertexes - 2;
  2263.         LineDefs[ NumLineDefs - 3].end = NumVertexes - 3;
  2264.         LineDefs[ NumLineDefs - 2].start = NumVertexes - 3;
  2265.         LineDefs[ NumLineDefs - 2].end = NumVertexes - 4;
  2266.         LineDefs[ NumLineDefs - 1].start = NumVertexes - 4;
  2267.         LineDefs[ NumLineDefs - 1].end = NumVertexes - 1;
  2268.      }
  2269.       }
  2270.       break;
  2271.    case 2:
  2272.       a = 8;
  2273.       b = 128;
  2274.       if (Input2Numbers( -1, -1, "Number of sides", "Radius", 32, 2000, &a, &b))
  2275.       {
  2276.      if (a < 3)
  2277.         a = 3;
  2278.      if (b < 8)
  2279.         b = 8;
  2280.      InsertPolygonVertices( xpos, ypos, a, b);
  2281.      if (sector < 0)
  2282.         InsertObject( OBJ_SECTORS, -1, 0, 0);
  2283.      for (n = 0; n < a; n++)
  2284.      {
  2285.         InsertObject( OBJ_LINEDEFS, -1, 0, 0);
  2286.         LineDefs[ NumLineDefs - 1].sidedef1 = NumSideDefs;
  2287.         InsertObject( OBJ_SIDEDEFS, -1, 0, 0);
  2288.         if (sector >= 0)
  2289.            SideDefs[ NumSideDefs - 1].sector = sector;
  2290.      }
  2291.      ObjectsNeeded( OBJ_LINEDEFS, 0);
  2292.      if (sector >= 0)
  2293.      {
  2294.         LineDefs[ NumLineDefs - 1].start = NumVertexes - 1;
  2295.         LineDefs[ NumLineDefs - 1].end = NumVertexes - a;
  2296.         for (n = 2; n <= a; n++)
  2297.         {
  2298.            LineDefs[ NumLineDefs - n].start = NumVertexes - n;
  2299.            LineDefs[ NumLineDefs - n].end = NumVertexes - n + 1;
  2300.         }
  2301.      }
  2302.      else
  2303.      {
  2304.         LineDefs[ NumLineDefs - 1].start = NumVertexes - a;
  2305.         LineDefs[ NumLineDefs - 1].end = NumVertexes - 1;
  2306.         for (n = 2; n <= a; n++)
  2307.         {
  2308.            LineDefs[ NumLineDefs - n].start = NumVertexes - n + 1;
  2309.            LineDefs[ NumLineDefs - n].end = NumVertexes - n;
  2310.         }
  2311.      }
  2312.       }
  2313.       break;
  2314.    case 3:
  2315. /*
  2316.       a = 6;
  2317.       b = 16;
  2318.       if (Input2Numbers( -1, -1, "Number of steps", "Step height", 32, 48, &a, &b))
  2319.       {
  2320.      if (a < 2)
  2321.         a = 2;
  2322.      ObjectsNeeded( OBJ_SECTORS, 0);
  2323.      n = Sectors[ sector].ceilh;
  2324.      h = Sectors[ sector].floorh;
  2325.      if (a * b < n - h)
  2326.      {
  2327.         Beep();
  2328.         Notify( -1, -1, "The stairs are too high for this Sector", NULL);
  2329.         return;
  2330.      }
  2331.      xpos = xpos - 32;
  2332.      ypos = ypos - 32 * a;
  2333.      for (n = 0; n < a; n++)
  2334.      {
  2335.         InsertObject( OBJ_VERTEXES, -1, xpos, ypos);
  2336.         InsertObject( OBJ_VERTEXES, -1, xpos + 64, ypos);
  2337.         InsertObject( OBJ_VERTEXES, -1, xpos + 64, ypos + 64);
  2338.         InsertObject( OBJ_VERTEXES, -1, xpos, ypos + 64);
  2339.         ypos += 64;
  2340.         InsertObject( OBJ_SECTORS, sector, 0, 0);
  2341.         h += b;
  2342.         Sectors[ NumSectors - 1].floorh = h;
  2343.  
  2344.         InsertObject( OBJ_LINEDEFS, -1, 0, 0);
  2345.         LineDefs[ NumLineDefs - 1].sidedef1 = NumSideDefs;
  2346.         LineDefs[ NumLineDefs - 1].sidedef2 = NumSideDefs + 1;
  2347.         InsertObject( OBJ_SIDEDEFS, -1, 0, 0);
  2348.         SideDefs[ NumSideDefs - 1].sector = sector;
  2349.         InsertObject( OBJ_SIDEDEFS, -1, 0, 0);
  2350.  
  2351.         ObjectsNeeded( OBJ_LINEDEFS, 0);
  2352.         LineDefs[ NumLineDefs - 4].start = NumVertexes - 4;
  2353.         LineDefs[ NumLineDefs - 4].end = NumVertexes - 3;
  2354.         LineDefs[ NumLineDefs - 3].start = NumVertexes - 3;
  2355.         LineDefs[ NumLineDefs - 3].end = NumVertexes - 2;
  2356.         LineDefs[ NumLineDefs - 2].start = NumVertexes - 2;
  2357.         LineDefs[ NumLineDefs - 2].end = NumVertexes - 1;
  2358.         LineDefs[ NumLineDefs - 1].start = NumVertexes - 1;
  2359.         LineDefs[ NumLineDefs - 1].end = NumVertexes - 4;
  2360.     }
  2361.       }
  2362.       break;
  2363. */
  2364.    case 4:
  2365.      NotImplemented();
  2366.      break;
  2367.    }
  2368. }
  2369.  
  2370.  
  2371.  
  2372. /*
  2373.    menu of miscellaneous operations
  2374. */
  2375.  
  2376. void MiscOperations( int x0, int y0, int objtype, SelPtr *list) /* SWAP! */
  2377. {
  2378.    char   msg[ 80];
  2379.    int    val;
  2380.    int    angle, scale;
  2381.  
  2382.    sprintf( msg, "Rotate and scale %s", GetEditModeName( objtype));
  2383.    if (objtype == OBJ_VERTEXES)
  2384.    {
  2385.       val = DisplayMenu( x0, y0, ((x0 == -1) ? "Misc. Operations" : NULL),
  2386.              "Find first free tag number",
  2387.              msg,
  2388.              "Delete Vertex and join LineDefs",
  2389.              "Merge several Vertices into one",
  2390.              "Add a LineDef and split Sector",
  2391.              NULL);
  2392.    }
  2393.    else if (objtype == OBJ_LINEDEFS)
  2394.    {
  2395.       val = DisplayMenu( x0, y0, ((x0 == -1) ? "Misc. Operations" : NULL),
  2396.              "Find first free tag number",
  2397.              msg,
  2398.              "Split LineDef (add new Vertex)",
  2399.              "Split LineDefs and Sector",
  2400.                          "Delete LineDefs and join Sectors",
  2401.              "Flip LineDef",
  2402.              "Swap SideDefs",
  2403.              "Align textures (Y offset)",
  2404.              "Align textures (X offset)",
  2405.              NULL);
  2406.    }
  2407.    else if (objtype == OBJ_SECTORS)
  2408.    {
  2409.       val = DisplayMenu( x0, y0, ((x0 == -1) ? "Misc. Operations" : NULL),
  2410.              "Find first free tag number",
  2411.              msg,
  2412.              "Make door from Sector",
  2413.              "Make lift from Sector",
  2414.              "Distribute Sector floor heights",
  2415.              "Distribute Sector ceiling heights",
  2416.              NULL);
  2417.    }
  2418.    else
  2419.    {
  2420.       val = DisplayMenu( x0, y0, ((x0 == -1) ? "Misc. Operations" : NULL),
  2421.              "Find first free tag number",
  2422.              msg,
  2423.              NULL);
  2424.    }
  2425.    if (val > 1 && *list == NULL)
  2426.    {
  2427.       Beep();
  2428.       sprintf( msg, "You must select at least one %s", GetObjectTypeName( objtype));
  2429.       Notify( -1, -1, msg, NULL);
  2430.       return;
  2431.    }
  2432.    switch (val)
  2433.    {
  2434.    case 1:
  2435.       sprintf( msg, "First free tag number: %d", FindFreeTag());
  2436.       Notify( -1, -1, msg, NULL);
  2437.       break;
  2438.    case 2:
  2439.       if ((objtype == OBJ_THINGS || objtype == OBJ_VERTEXES) && (*list)->next == NULL)
  2440.       {
  2441.      Beep();
  2442.      sprintf( msg, "You must select more than one %s", GetObjectTypeName( objtype));
  2443.      Notify( -1, -1, msg, NULL);
  2444.      return;
  2445.       }
  2446.       angle = 0;
  2447.       scale = 100;
  2448.       if (Input2Numbers( -1, -1, "rotation angle (°)", "scale (%)", 360, 1000, &angle, &scale))
  2449.      RotateAndScaleObjects( objtype, *list, (double) angle * 0.0174533, (double) scale * 0.01);
  2450.       break;
  2451.    case 3:
  2452.       if (objtype == OBJ_VERTEXES)
  2453.       {
  2454.      DeleteVerticesJoinLineDefs( *list);
  2455.      ForgetSelection( list);
  2456.       }
  2457.       else if (objtype == OBJ_LINEDEFS)
  2458.       {
  2459.      SplitLineDefs( *list);
  2460.       }
  2461.       else if (objtype == OBJ_SECTORS)
  2462.       {
  2463.      if ((*list)->next != NULL)
  2464.      {
  2465.         Beep();
  2466.         Notify( -1, -1, "You must select exactly one Sector", NULL);
  2467.      }
  2468.      else
  2469.      {
  2470.         MakeDoorFromSector( (*list)->objnum);
  2471.      }
  2472.       }
  2473.       break;
  2474.    case 4:
  2475.       if (objtype == OBJ_VERTEXES)
  2476.       {
  2477.      MergeVertices( list);
  2478.       }
  2479.       else if (objtype == OBJ_LINEDEFS)
  2480.       {
  2481.      if ((*list)->next == NULL || (*list)->next->next != NULL)
  2482.      {
  2483.         Beep();
  2484.         Notify( -1, -1, "You must select exactly two LineDefs", NULL);
  2485.      }
  2486.      else
  2487.      {
  2488.         SplitLineDefsAndSector( (*list)->objnum, (*list)->next->objnum);
  2489.         ForgetSelection( list);
  2490.      }
  2491.       }
  2492.       else if (objtype == OBJ_SECTORS)
  2493.       {
  2494.      if ((*list)->next != NULL)
  2495.      {
  2496.         Beep();
  2497.         Notify( -1, -1, "You must select exactly one Sector", NULL);
  2498.      }
  2499.      else
  2500.      {
  2501.         MakeLiftFromSector( (*list)->objnum);
  2502.      }
  2503.       }
  2504.       break;
  2505.    case 5:
  2506.       if (objtype == OBJ_VERTEXES)
  2507.       {
  2508.      if ((*list)->next == NULL || (*list)->next->next != NULL)
  2509.      {
  2510.         Beep();
  2511.         Notify( -1, -1, "You must select exactly two Vertices", NULL);
  2512.      }
  2513.      else
  2514.      {
  2515.         SplitSector( (*list)->objnum, (*list)->next->objnum);
  2516.         ForgetSelection( list);
  2517.      }
  2518.       }
  2519.       else if (objtype == OBJ_LINEDEFS)
  2520.       {
  2521.          DeleteLineDefsJoinSectors( list);
  2522.       }
  2523.       else if (objtype == OBJ_SECTORS)
  2524.       {
  2525.      if ((*list)->next == NULL || (*list)->next->next == NULL)
  2526.      {
  2527.         Beep();
  2528.         Notify( -1, -1, "You must select three or more Sectors", NULL);
  2529.      }
  2530.      else
  2531.      {
  2532.         DistributeSectorFloors( *list);
  2533.      }
  2534.       }
  2535.       break;
  2536.    case 6:
  2537.       if (objtype == OBJ_LINEDEFS)
  2538.       {
  2539.      FlipLineDefs( *list, TRUE);
  2540.       }
  2541.       else if (objtype == OBJ_SECTORS)
  2542.       {
  2543.      if ((*list)->next == NULL || (*list)->next->next == NULL)
  2544.      {
  2545.         Beep();
  2546.         Notify( -1, -1, "You must select three or more Sectors", NULL);
  2547.      }
  2548.      else
  2549.      {
  2550.         DistributeSectorCeilings( *list);
  2551.      }
  2552.       }
  2553.       break;
  2554.    case 7:
  2555.       if (objtype == OBJ_LINEDEFS)
  2556.       {
  2557.      if (Expert || Confirm( -1, -1, "Warning: the Sector references are also swapped", "You may get strange results if you don't know what you are doing..."))
  2558.         FlipLineDefs( *list, FALSE);
  2559.       }
  2560.       break;
  2561.    case 8:
  2562.       if (objtype == OBJ_LINEDEFS)
  2563.       {
  2564.      SelPtr sdlist, cur;
  2565.  
  2566.      /* select all SideDefs */
  2567.      ObjectsNeeded( OBJ_LINEDEFS);
  2568.      sdlist = NULL;
  2569.      for (cur = *list; cur; cur = cur->next)
  2570.      {
  2571.         if (LineDefs[ cur->objnum].sidedef1 >= 0)
  2572.            SelectObject( &sdlist, LineDefs[ cur->objnum].sidedef1);
  2573.         if (LineDefs[ cur->objnum].sidedef2 >= 0)
  2574.            SelectObject( &sdlist, LineDefs[ cur->objnum].sidedef2);
  2575.      }
  2576.      /* align the textures along the Y axis (height) */
  2577.      AlignTexturesY( &sdlist);
  2578.       }
  2579.    case 9:
  2580.       if (objtype == OBJ_LINEDEFS)
  2581.       {
  2582.      SelPtr sdlist, cur;
  2583.  
  2584.      /* select all SideDefs */
  2585.      ObjectsNeeded( OBJ_LINEDEFS,0);
  2586.      sdlist = NULL;
  2587.      for (cur = *list; cur; cur = cur->next)
  2588.      {
  2589.         if (LineDefs[ cur->objnum].sidedef1 >= 0)
  2590.            SelectObject( &sdlist, LineDefs[ cur->objnum].sidedef1);
  2591.         if (LineDefs[ cur->objnum].sidedef2 >= 0)
  2592.            SelectObject( &sdlist, LineDefs[ cur->objnum].sidedef2);
  2593.      }
  2594.      /* align the textures along the X axis (width) */
  2595.      AlignTexturesX( &sdlist);
  2596.       }
  2597.       break;
  2598.    }
  2599. }
  2600.  
  2601.  
  2602.  
  2603. /*
  2604.    display a "Preferences" menu (change default textures, etc.)
  2605. */
  2606.  
  2607. void Preferences( int x0, int y0)
  2608. {
  2609.    char   *menustr[ 30];
  2610.    int     dummy[ 30];
  2611.    int     n, val;
  2612.    char    texname[ 9];
  2613.  
  2614.    if (x0 < 0)
  2615.       x0 = (ScrMaxX - 50 * 8 - 19) / 2;
  2616.    if (y0 < 0)
  2617.       y0 = (ScrMaxY - 5 * 10 - 28) / 2;
  2618.    for (n = 0; n < 8; n++)
  2619.       menustr[ n] = GetMemory( 80);
  2620.    sprintf( menustr[ 7], "Preferences");
  2621.    sprintf( menustr[ 0], "Change default wall texture    (Current: %s)", DefaultWallTexture);
  2622.    sprintf( menustr[ 1], "Change default \"upper\" texture (Current: %s)", DefaultUpperTexture);
  2623.    sprintf( menustr[ 2], "Change default \"lower\" texture (Current: %s)", DefaultLowerTexture);
  2624.    sprintf( menustr[ 3], "Change default floor texture   (Current: %s)", DefaultFloorTexture);
  2625.    sprintf( menustr[ 4], "Change default ceiling texture (Current: %s)", DefaultCeilingTexture);
  2626.    sprintf( menustr[ 5], "Change default floor height    (Current: %d)", DefaultFloorHeight);
  2627.    sprintf( menustr[ 6], "Change default ceiling height  (Current: %d)", DefaultCeilingHeight);
  2628.    val = DisplayMenuArray( x0, y0, menustr[ 7], 7, NULL, menustr, dummy);
  2629.    for (n = 0; n < 8; n++)
  2630.       FreeMemory( menustr[ n]);
  2631.    switch (val)
  2632.    {
  2633.    case 1:
  2634.       strcpy( texname, DefaultWallTexture);
  2635.       ChooseWallTexture( x0 + 42, y0 + 34, "Choose a wall texture", NumWTexture, WTexture, texname);
  2636.       if (strlen( texname) > 0)
  2637.      strcpy( DefaultWallTexture, texname);
  2638.       break;
  2639.    case 2:
  2640.       strcpy( texname, DefaultUpperTexture);
  2641.       ChooseWallTexture( x0 + 42, y0 + 34, "Choose a wall texture", NumWTexture, WTexture, texname);
  2642.       if (strlen( texname) > 0)
  2643.      strcpy( DefaultUpperTexture, texname);
  2644.       break;
  2645.    case 3:
  2646.       strcpy( texname, DefaultLowerTexture);
  2647.       ChooseWallTexture( x0 + 42, y0 + 34, "Choose a wall texture", NumWTexture, WTexture, texname);
  2648.       if (strlen( texname) > 0)
  2649.      strcpy( DefaultLowerTexture, texname);
  2650.       break;
  2651.    case 4:
  2652.       strcpy( texname, DefaultFloorTexture);
  2653.       ChooseFloorTexture( x0 + 42, y0 + 44, "Choose a floor texture", NumFTexture, FTexture, texname);
  2654.       if (strlen( texname) > 0)
  2655.      strcpy( DefaultFloorTexture, texname);
  2656.       break;
  2657.    case 5:
  2658.       strcpy( texname, DefaultCeilingTexture);
  2659.       ChooseFloorTexture( x0 + 42, y0 + 54, "Choose a ceiling texture", NumFTexture, FTexture, texname);
  2660.       if (strlen( texname) > 0)
  2661.      strcpy( DefaultCeilingTexture, texname);
  2662.       break;
  2663.    case 6:
  2664.       val = InputIntegerValue( x0 + 42, y0 + 64, -512, 511, DefaultFloorHeight);
  2665.       if (val >= -512)
  2666.      DefaultFloorHeight = val;
  2667.       break;
  2668.    case 7:
  2669.       val = InputIntegerValue( x0 + 42, y0 + 74, -512, 511, DefaultCeilingHeight);
  2670.       if (val >= -512)
  2671.      DefaultCeilingHeight = val;
  2672.       break;
  2673.    }
  2674. }
  2675.  
  2676.  
  2677. /* end of file */
  2678.