home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the DOOM Programming Gurus / Tricks_of_the_Doom_Programming_Gurus.iso / bonus / editors / deth / source / objects.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-02  |  72.2 KB  |  2,544 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.    OBJECTS.C - object handling routines.
  11.    */
  12.  
  13. /* the includes */
  14. #include "deu.h"
  15. #include "levels.h"
  16.  
  17. /*
  18.    highlight the selected objects
  19.    */
  20.  
  21. void HighlightSelection( BCINT objtype, SelPtr list) /* SWAP! */
  22. {
  23.     SelPtr cur;
  24.     
  25.     if (list == NULL)
  26.     return;
  27.     for (cur = list; cur; cur = cur->next)
  28.     HighlightObject( objtype, cur->objnum, GREEN);
  29. }
  30.  
  31.  
  32.  
  33. /*
  34.    test if an object is in the selection list
  35.    */
  36.  
  37. Bool IsSelected( SelPtr list, BCINT objnum)
  38. {
  39.     SelPtr cur;
  40.     
  41.     if (list == NULL)
  42.     return FALSE;
  43.     for (cur = list; cur; cur = cur->next)
  44.     if (cur->objnum == objnum)
  45.         return TRUE;
  46.     return FALSE;
  47. }
  48.  
  49.  
  50.  
  51. /*
  52.    add an object to the selection list
  53.    */
  54.  
  55. void SelectObject( SelPtr *list, BCINT objnum)
  56. {
  57.     SelPtr cur;
  58.     
  59.     if (objnum < 0)
  60.     ProgError( "BUG: SelectObject called with %d", objnum);
  61.     cur = (SelPtr) GetMemory( sizeof( struct SelectionList));
  62.     cur->next = *list;
  63.     cur->objnum = objnum;
  64.     *list = cur;
  65. }
  66.  
  67.  
  68.  
  69. /*
  70.    remove an object from the selection list
  71.    */
  72.  
  73. void UnSelectObject( SelPtr *list, BCINT objnum)
  74. {
  75.     SelPtr cur, prev;
  76.     
  77.     if (objnum < 0)
  78.     ProgError( "BUG: UnSelectObject called with %d", objnum);
  79.     prev = NULL;
  80.     cur = *list;
  81.     while (cur) {
  82.     if (cur->objnum == objnum) {
  83.         if (prev)
  84.         prev->next = cur->next;
  85.         else
  86.         *list = cur->next;
  87.         FreeMemory( cur);
  88.         if (prev)
  89.         cur = prev->next;
  90.         else
  91.         cur = *list;
  92.     }
  93.     else {
  94.         prev = cur;
  95.         cur = cur->next;
  96.     }
  97.     }
  98. }
  99.  
  100.  
  101.  
  102. /*
  103.    forget the selection list
  104.    */
  105.  
  106. void ForgetSelection( SelPtr *list)
  107. {
  108.     SelPtr cur, prev;
  109.     
  110.     cur = *list;
  111.     while (cur) {
  112.     prev = cur;
  113.     cur = cur->next;
  114.     FreeMemory( prev);
  115.     }
  116.     *list = NULL;
  117. }
  118.  
  119.  
  120.  
  121. /*
  122.    get the number of objets of a given type minus one
  123.    */
  124. BCINT GetMaxObjectNum( BCINT objtype)
  125. {
  126.     switch (objtype) {
  127.     case OBJ_THINGS:
  128.     return NumThings - 1;
  129.     case OBJ_LINEDEFS:
  130.     return NumLineDefs - 1;
  131.     case OBJ_SIDEDEFS:
  132.     return NumSideDefs - 1;
  133.     case OBJ_VERTEXES:
  134.     return NumVertexes - 1;
  135.     case OBJ_SEGS:
  136.     return NumSegs - 1;
  137.     case OBJ_SSECTORS:
  138.     return NumSSectors - 1;
  139.     case OBJ_SECTORS:
  140.     return NumSectors - 1;
  141.     }
  142.     return -1;
  143. }
  144.  
  145.  
  146. /*
  147.    check if there is something of interest inside the given box
  148.    */
  149.  
  150. BCINT GetCurObject( BCINT objtype, BCINT x0, BCINT y0, BCINT x1, BCINT y1) /* SWAP! */
  151. {
  152.     BCINT n, m, cur, curx;
  153.     BCINT lx0, ly0, lx1, ly1;
  154.     BCINT midx, midy;
  155.     
  156.     cur = -1;
  157.     if (x1 < x0) {
  158.     n = x0;
  159.     x0 = x1;
  160.     x1 = n;
  161.     }
  162.     if (y1 < y0) {
  163.     n = y0;
  164.     y0 = y1;
  165.     y1 = n;
  166.     }
  167.     
  168.     switch (objtype) {
  169.     case OBJ_THINGS:
  170.     ObjectsNeeded( OBJ_THINGS, 0);
  171.     for (n = 0; n < NumThings; n++)
  172.         if (Things[ n].xpos >= x0 && Things[ n].xpos <= x1 && Things[ n].ypos >= y0 && Things[ n].ypos <= y1) {
  173.         cur = n;
  174.         break;
  175.         }
  176.     break;
  177.     case OBJ_VERTEXES:
  178.     ObjectsNeeded( OBJ_VERTEXES, 0);
  179.     for (n = 0; n < NumVertexes; n++)
  180.         if (Vertexes[ n].x >= x0 && Vertexes[ n].x <= x1 && Vertexes[ n].y >= y0 && Vertexes[ n].y <= y1) {
  181.         cur = n;
  182.         break;
  183.         }
  184.     break;
  185.     case OBJ_LINEDEFS:
  186.     ObjectsNeeded( OBJ_LINEDEFS, OBJ_VERTEXES, 0);
  187.     for (n = 0; n < NumLineDefs; n++) {
  188.         if (IsLineDefInside( n, x0, y0, x1, y1)) {
  189.         cur = n;
  190.         break;
  191.         }
  192.     }
  193.     break;
  194.     case OBJ_SECTORS:
  195.     /* hack, hack...  I look for the first LineDef crossing a horizontal half-line drawn from the cursor */
  196.     ObjectsNeeded( OBJ_LINEDEFS, OBJ_VERTEXES, 0);
  197.     curx = MapMaxX + 1;
  198.     cur = -1;
  199.     midx = (x0 + x1) / 2;
  200.     midy = (y0 + y1) / 2;
  201.     for (n = 0; n < NumLineDefs; n++)
  202.         if ((Vertexes[ LineDefs[ n].start].y > midy) != (Vertexes[ LineDefs[ n].end].y > midy)) {
  203.         lx0 = Vertexes[ LineDefs[ n].start].x;
  204.         ly0 = Vertexes[ LineDefs[ n].start].y;
  205.         lx1 = Vertexes[ LineDefs[ n].end].x;
  206.         ly1 = Vertexes[ LineDefs[ n].end].y;
  207.         m = lx0 + (BCINT) ((long) (midy - ly0) * (long) (lx1 - lx0) / (long) (ly1 - ly0));
  208.         if (m >= midx && m < curx) {
  209.             curx = m;
  210.             cur = n;
  211.         }
  212.         }
  213.     /* now look if this LineDef has a SideDef bound to one sector */
  214.     if (cur >= 0) {
  215.         if (Vertexes[ LineDefs[ cur].start].y > Vertexes[ LineDefs[ cur].end].y)
  216.         cur = LineDefs[ cur].sidedef1;
  217.         else
  218.         cur = LineDefs[ cur].sidedef2;
  219.         if (cur >= 0) {
  220.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  221.         cur = SideDefs[ cur].sector;
  222.         }
  223.         else
  224.         cur = -1;
  225.     }
  226.     else
  227.         cur = -1;
  228.     break;
  229.     }
  230.     return cur;
  231. }
  232.  
  233.  
  234.  
  235. /*
  236.    select all objects inside a given box
  237.    */
  238.  
  239. SelPtr SelectObjectsInBox( BCINT objtype, BCINT x0, BCINT y0, BCINT x1, BCINT y1) /* SWAP! */
  240. {
  241.     BCINT n, m;
  242.     SelPtr list;
  243.     
  244.     list = NULL;
  245.     if (x1 < x0) {
  246.     n = x0;
  247.     x0 = x1;
  248.     x1 = n;
  249.     }
  250.     if (y1 < y0) {
  251.     n = y0;
  252.     y0 = y1;
  253.     y1 = n;
  254.     }
  255.     
  256.     switch (objtype) {
  257.     case OBJ_THINGS:
  258.     ObjectsNeeded( OBJ_THINGS, 0);
  259.     for (n = 0; n < NumThings; n++)
  260.         if (Things[ n].xpos >= x0 && Things[ n].xpos <= x1 && Things[ n].ypos >= y0 && Things[ n].ypos <= y1)
  261.         SelectObject( &list, n);
  262.     break;
  263.     case OBJ_VERTEXES:
  264.     ObjectsNeeded( OBJ_VERTEXES, 0);
  265.     for (n = 0; n < NumVertexes; n++)
  266.         if (Vertexes[ n].x >= x0 && Vertexes[ n].x <= x1 && Vertexes[ n].y >= y0 && Vertexes[ n].y <= y1)
  267.         SelectObject( &list, n);
  268.     break;
  269.     case OBJ_LINEDEFS:
  270.     ObjectsNeeded( OBJ_LINEDEFS, OBJ_VERTEXES, 0);
  271.     for (n = 0; n < NumLineDefs; n++) {
  272.         /* the two ends of the line must be in the box */
  273.         m = LineDefs[ n].start;
  274.         if (Vertexes[ m].x < x0 || Vertexes[ m].x > x1 || Vertexes[ m].y < y0 || Vertexes[ m].y > y1)
  275.         continue;
  276.         m = LineDefs[ n].end;
  277.         if (Vertexes[ m].x < x0 || Vertexes[ m].x > x1 || Vertexes[ m].y < y0 || Vertexes[ m].y > y1)
  278.         continue;
  279.         SelectObject( &list, n);
  280.     }
  281.     break;
  282.     case OBJ_SECTORS:
  283.     /* hack: select all sectors... */
  284.     for (n = 0; n < NumSectors; n++)
  285.         SelectObject( &list, n);
  286.     /* ... then remove the unwanted ones from the list */
  287.     ObjectsNeeded( OBJ_LINEDEFS, OBJ_SIDEDEFS, OBJ_VERTEXES, 0);
  288.     for (n = 0; n < NumLineDefs; n++) {
  289.         m = LineDefs[ n].start;
  290.         if (Vertexes[ m].x < x0 || Vertexes[ m].x > x1 || Vertexes[ m].y < y0 || Vertexes[ m].y > y1) {
  291.         m = LineDefs[ n].sidedef1;
  292.         if (m >= 0 && SideDefs[ m].sector >= 0)
  293.             UnSelectObject( &list, SideDefs[ m].sector);
  294.         m = LineDefs[ n].sidedef2;
  295.         if (m >= 0 && SideDefs[ m].sector >= 0)
  296.             UnSelectObject( &list, SideDefs[ m].sector);
  297.         continue;
  298.         }
  299.         m = LineDefs[ n].end;
  300.         if (Vertexes[ m].x < x0 || Vertexes[ m].x > x1 || Vertexes[ m].y < y0 || Vertexes[ m].y > y1) {
  301.         m = LineDefs[ n].sidedef1;
  302.         if (m >= 0 && SideDefs[ m].sector >= 0)
  303.             UnSelectObject( &list, SideDefs[ m].sector);
  304.         m = LineDefs[ n].sidedef2;
  305.         if (m >= 0 && SideDefs[ m].sector >= 0)
  306.             UnSelectObject( &list, SideDefs[ m].sector);
  307.         continue;
  308.         }
  309.     }
  310.     break;
  311.     }
  312.     return list;
  313. }
  314.  
  315.  
  316.  
  317. /*
  318.    highlight the selected object
  319.    */
  320.  
  321. void HighlightObject( BCINT objtype, BCINT objnum, BCINT color) /* SWAP! */
  322. {
  323.     BCINT  n, m;
  324.     
  325.     /* use XOR mode : drawing any line twice erases it */
  326.     setwritemode( XOR_PUT);
  327.     SetColor( color);
  328.     switch ( objtype) {
  329.     case OBJ_THINGS:
  330.     ObjectsNeeded( OBJ_THINGS, 0);
  331.     m = (GetThingRadius( Things[ objnum].type) * 3) / 2;
  332.     DrawMapLine( Things[ objnum].xpos - m, Things[ objnum].ypos - m, Things[ objnum].xpos - m, Things[ objnum].ypos + m);
  333.     DrawMapLine( Things[ objnum].xpos - m, Things[ objnum].ypos + m, Things[ objnum].xpos + m, Things[ objnum].ypos + m);
  334.     DrawMapLine( Things[ objnum].xpos + m, Things[ objnum].ypos + m, Things[ objnum].xpos + m, Things[ objnum].ypos - m);
  335.     DrawMapLine( Things[ objnum].xpos + m, Things[ objnum].ypos - m, Things[ objnum].xpos - m, Things[ objnum].ypos - m);
  336.     if    (ThingAngle == FALSE)
  337.         DrawMapArrow( Things[ objnum].xpos, Things[ objnum].ypos, Things[ objnum].angle * 182);
  338.     break;
  339.     case OBJ_LINEDEFS:
  340.     ObjectsNeeded( OBJ_LINEDEFS, OBJ_VERTEXES, 0);
  341.     n = (Vertexes[ LineDefs[ objnum].start].x + Vertexes[ LineDefs[ objnum].end].x) / 2;
  342.     m = (Vertexes[ LineDefs[ objnum].start].y + Vertexes[ LineDefs[ objnum].end].y) / 2;
  343.     DrawMapLine( n, m, n + (Vertexes[ LineDefs[ objnum].end].y - Vertexes[ LineDefs[ objnum].start].y) / 3, m + (Vertexes[ LineDefs[ objnum].start].x - Vertexes[ LineDefs[ objnum].end].x) / 3);
  344.     setlinestyle(SOLID_LINE, 0, 2 );  /* AJB */
  345.     DrawMapVector( Vertexes[ LineDefs[ objnum].start].x, Vertexes[ LineDefs[ objnum].start].y,
  346.               Vertexes[ LineDefs[ objnum].end].x, Vertexes[ LineDefs[ objnum].end].y);
  347.     if (color != LIGHTRED && LineDefs[ objnum].tag > 0) {
  348.         for (m = 0; m < NumSectors; m++)
  349.         if (Sectors[ m].tag == LineDefs[ objnum].tag)
  350.             HighlightObject( OBJ_SECTORS, m, LIGHTRED);
  351.     }
  352.     setlinestyle(SOLID_LINE, 0, NORM_WIDTH);
  353.     break;
  354.     case OBJ_VERTEXES:
  355.     ObjectsNeeded( OBJ_VERTEXES, 0);
  356.     DrawMapLine( Vertexes[ objnum].x - OBJSIZE * 2, Vertexes[ objnum].y - OBJSIZE * 2, Vertexes[ objnum].x - OBJSIZE * 2, Vertexes[ objnum].y + OBJSIZE * 2);
  357.     DrawMapLine( Vertexes[ objnum].x - OBJSIZE * 2, Vertexes[ objnum].y + OBJSIZE * 2, Vertexes[ objnum].x + OBJSIZE * 2, Vertexes[ objnum].y + OBJSIZE * 2);
  358.     DrawMapLine( Vertexes[ objnum].x + OBJSIZE * 2, Vertexes[ objnum].y + OBJSIZE * 2, Vertexes[ objnum].x + OBJSIZE * 2, Vertexes[ objnum].y - OBJSIZE * 2);
  359.     DrawMapLine( Vertexes[ objnum].x + OBJSIZE * 2, Vertexes[ objnum].y - OBJSIZE * 2, Vertexes[ objnum].x - OBJSIZE * 2, Vertexes[ objnum].y - OBJSIZE * 2);
  360.     break;
  361.     case OBJ_SECTORS:
  362.     ObjectsNeeded( OBJ_LINEDEFS, OBJ_SIDEDEFS, OBJ_VERTEXES, 0);
  363.     setlinestyle(SOLID_LINE, 0, 2 );  /* AJB */
  364.     for (n = 0; n < NumLineDefs; n++)
  365.         if ( (LineDefs[n].sidedef1>=0 && SideDefs[LineDefs[n].sidedef1].sector == objnum ) ||
  366.         (LineDefs[n].sidedef2>=0 && SideDefs[LineDefs[n].sidedef2].sector == objnum ))
  367.         DrawMapLine( Vertexes[ LineDefs[ n].start].x, Vertexes[ LineDefs[ n].start].y,
  368.                 Vertexes[ LineDefs[ n].end].x, Vertexes[ LineDefs[ n].end].y);
  369.     if (color != LIGHTRED && Sectors[ objnum].tag > 0) {
  370.         for (m = 0; m < NumLineDefs; m++)
  371.         if (LineDefs[ m].tag == Sectors[ objnum].tag) {
  372.             setlinestyle(SOLID_LINE, 0, NORM_WIDTH);
  373.             HighlightObject( OBJ_LINEDEFS, m, LIGHTRED);
  374.             }
  375.     } 
  376.     setlinestyle(SOLID_LINE, 0, NORM_WIDTH);
  377.     break;
  378.     }
  379.     /* restore normal write mode */
  380.     setwritemode( COPY_PUT);
  381. }
  382.  
  383.  
  384.  
  385. /*
  386.    delete an object
  387.    */
  388.  
  389. void DeleteObject( BCINT objtype, BCINT objnum) /* SWAP! */
  390. {
  391.     SelPtr list;
  392.     
  393.     list = NULL;
  394.     SelectObject( &list, objnum);
  395.     DeleteObjects( objtype, &list);
  396. }
  397.  
  398.  
  399.  
  400. /*
  401.    delete a group of objects (*recursive*)
  402.    */
  403.  
  404. void DeleteObjects( BCINT objtype, SelPtr *list) /* SWAP! */
  405. {
  406.     BCINT    n, objnum;
  407.     SelPtr cur;
  408.     
  409.     MadeChanges = TRUE;
  410.     switch (objtype) {
  411.     case OBJ_THINGS:
  412.     ObjectsNeeded( OBJ_THINGS, 0);
  413.     while (*list) {
  414.         objnum = (*list)->objnum;
  415.         /* delete the Thing */
  416.         NumThings--;
  417.         if (NumThings > 0) {
  418.         for (n = objnum; n < NumThings; n++)
  419.             Things[ n] = Things[ n + 1];
  420.         Things = (TPtr) ResizeFarMemory( Things, NumThings * sizeof( struct Thing));
  421.         }
  422.         else {
  423.         FreeFarMemory( Things);
  424.         Things = NULL;
  425.         }
  426.         for (cur = (*list)->next; cur; cur = cur->next)
  427.         if (cur->objnum > objnum)
  428.             cur->objnum--;
  429.         UnSelectObject( list, objnum);
  430.     }
  431.     break;
  432.     case OBJ_VERTEXES:
  433.     while (*list) {
  434.         objnum = (*list)->objnum;
  435.         /* delete the LineDefs bound to this Vertex and change the references */
  436.         ObjectsNeeded( OBJ_LINEDEFS, 0);
  437.         for (n = 0; n < NumLineDefs; n++) {
  438.         if (LineDefs[ n].start == objnum || LineDefs[ n].end == objnum)
  439.             DeleteObject( OBJ_LINEDEFS, n--);
  440.         else {
  441.             if (LineDefs[ n].start >= objnum)
  442.             LineDefs[ n].start--;
  443.             if (LineDefs[ n].end >= objnum)
  444.             LineDefs[ n].end--;
  445.         }
  446.         }
  447.         /* delete the Vertex */
  448.         ObjectsNeeded( OBJ_VERTEXES, 0);
  449.         NumVertexes--;
  450.         if (NumVertexes > 0) {
  451.         for (n = objnum; n < NumVertexes; n++)
  452.             Vertexes[ n] = Vertexes[ n + 1];
  453.         Vertexes = (VPtr) ResizeFarMemory( Vertexes, NumVertexes * sizeof( struct Vertex));
  454.         }
  455.         else {
  456.         FreeFarMemory( Vertexes);
  457.         Vertexes = NULL;
  458.         }
  459.         for (cur = (*list)->next; cur; cur = cur->next)
  460.         if (cur->objnum > objnum)
  461.             cur->objnum--;
  462.         UnSelectObject( list, objnum);
  463.     }
  464.     break;
  465.     case OBJ_LINEDEFS:
  466.     while (*list) {
  467.         ObjectsNeeded( OBJ_LINEDEFS, 0);
  468.         objnum = (*list)->objnum;
  469.         /* delete the two SideDefs bound to this LineDef */
  470.         if (LineDefs[ objnum].sidedef1 >= 0) {
  471.         DeleteObject( OBJ_SIDEDEFS, LineDefs[ objnum].sidedef1);
  472.         ObjectsNeeded( OBJ_LINEDEFS, 0);
  473.         }
  474.         if (LineDefs[ objnum].sidedef2 >= 0) {
  475.         DeleteObject( OBJ_SIDEDEFS, LineDefs[ objnum].sidedef2);
  476.         ObjectsNeeded( OBJ_LINEDEFS, 0);
  477.         }
  478.         /* delete the LineDef */
  479.         NumLineDefs--;
  480.         if (NumLineDefs > 0) {
  481.         for (n = objnum; n < NumLineDefs; n++)
  482.             LineDefs[ n] = LineDefs[ n + 1];
  483.         LineDefs = (LDPtr) ResizeFarMemory( LineDefs, NumLineDefs * sizeof( struct LineDef));
  484.         }
  485.         else {
  486.         FreeFarMemory( LineDefs);
  487.         LineDefs = NULL;
  488.         }
  489.         for (cur = (*list)->next; cur; cur = cur->next)
  490.         if (cur->objnum > objnum)
  491.             cur->objnum--;
  492.         UnSelectObject( list, objnum);
  493.     }
  494.     break;
  495.     case OBJ_SIDEDEFS:
  496.     while (*list) {
  497.         objnum = (*list)->objnum;
  498.         /* change the LineDefs references */
  499.         ObjectsNeeded( OBJ_LINEDEFS, 0);
  500.         for (n = 0; n < NumLineDefs; n++) {
  501.         if (LineDefs[ n].sidedef1 == objnum)
  502.             LineDefs[ n].sidedef1 = -1;
  503.         else if (LineDefs[ n].sidedef1 >= objnum)
  504.             LineDefs[ n].sidedef1--;
  505.         if (LineDefs[ n].sidedef2 == objnum)
  506.             LineDefs[ n].sidedef2 = -1;
  507.         else if (LineDefs[ n].sidedef2 >= objnum)
  508.             LineDefs[ n].sidedef2--;
  509.         }
  510.         /* delete the SideDef */
  511.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  512.         NumSideDefs--;
  513.         if (NumSideDefs > 0) {
  514.         for (n = objnum; n < NumSideDefs; n++)
  515.             SideDefs[ n] = SideDefs[ n + 1];
  516.         SideDefs = (SDPtr) ResizeFarMemory( SideDefs, NumSideDefs * sizeof( struct SideDef));
  517.         }
  518.         else {
  519.         FreeFarMemory( SideDefs);
  520.         SideDefs = NULL;
  521.         }
  522.         for (cur = (*list)->next; cur; cur = cur->next)
  523.         if (cur->objnum > objnum)
  524.             cur->objnum--;
  525.         UnSelectObject( list, objnum);
  526.     }
  527.     MadeMapChanges = TRUE;
  528.     break;
  529.     case OBJ_SECTORS:
  530.     while (*list) {
  531.         objnum = (*list)->objnum;
  532.         /* delete the SideDefs bound to this Sector and change the references */
  533.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  534.         for (n = 0; n < NumSideDefs; n++)
  535.         if (SideDefs[ n].sector == objnum)
  536.             DeleteObject( OBJ_SIDEDEFS, n--);
  537.         else if (SideDefs[ n].sector >= objnum)
  538.             SideDefs[ n].sector--;
  539.         /* delete the Sector */
  540.         ObjectsNeeded( OBJ_SECTORS, 0);
  541.         NumSectors--;
  542.         if (NumSectors > 0) {
  543.         for (n = objnum; n < NumSectors; n++)
  544.             Sectors[ n] = Sectors[ n + 1];
  545.         Sectors = (SPtr) ResizeFarMemory( Sectors, NumSectors * sizeof( struct Sector));
  546.         }
  547.         else {
  548.         FreeFarMemory( Sectors);
  549.         Sectors = NULL;
  550.         }
  551.         for (cur = (*list)->next; cur; cur = cur->next)
  552.         if (cur->objnum > objnum)
  553.             cur->objnum--;
  554.         UnSelectObject( list, objnum);
  555.     }
  556.     break;
  557.     default:
  558.     Beep();
  559.     }
  560. }
  561.  
  562.  
  563.  
  564. /*
  565.    insert a new object
  566.    */
  567.  
  568.  
  569. void InsertObject(BCINT objtype, BCINT copyfrom, BCINT xpos, BCINT ypos) /* SWAP! */
  570. {
  571.     BCINT last;
  572.     
  573.     ObjectsNeeded( objtype, 0);
  574.     MadeChanges = TRUE;
  575.     switch (objtype) {
  576.     case OBJ_THINGS:
  577.     last = NumThings++;
  578.     if (last > 0)
  579.         Things = (TPtr) ResizeFarMemory( Things, (unsigned long) NumThings * sizeof( struct Thing));
  580.     else
  581.         Things = (TPtr) GetFarMemory( sizeof( struct Thing));
  582.     Things[ last].xpos = xpos;
  583.     Things[ last].ypos = ypos;
  584.     if (copyfrom >= 0) {
  585.         Things[ last].type  = Things[ copyfrom].type;
  586.         Things[ last].angle = Things[ copyfrom].angle;
  587.         Things[ last].when  = Things[ copyfrom].when;
  588.     }
  589.     else {
  590.         Things[ last].type  = 0;
  591.         Things[ last].angle = 0;
  592.         Things[ last].when  = 0x07;
  593.     }
  594.     break;
  595.     case OBJ_VERTEXES:
  596.     last = NumVertexes++;
  597.     if (last > 0)
  598.         Vertexes = (VPtr) ResizeFarMemory( Vertexes, (unsigned long) NumVertexes * sizeof( struct Vertex));
  599.     else
  600.         Vertexes = (VPtr) GetFarMemory( sizeof( struct Vertex));
  601.     /* kluge: the Nodes builder will put -2 in copyfrom */
  602.     if (copyfrom == -2) {
  603.         Vertexes[ last].x = xpos;
  604.         Vertexes[ last].y = ypos;
  605.     }
  606.     else {
  607.         Vertexes[ last].x = xpos & ~7;
  608.         Vertexes[ last].y = ypos & ~7;
  609.         if (Vertexes[ last].x < MapMinX)
  610.         MapMinX = Vertexes[ last].x;
  611.         if (Vertexes[ last].x > MapMaxX)
  612.         MapMaxX = Vertexes[ last].x;
  613.         if (Vertexes[ last].y < MapMinY)
  614.         MapMinY = Vertexes[ last].y;
  615.         if (Vertexes[ last].y > MapMaxY)
  616.         MapMaxY = Vertexes[ last].y;
  617.         MadeMapChanges = TRUE;
  618.     }
  619.     break;
  620.     case OBJ_LINEDEFS:
  621.     last = NumLineDefs++;
  622.     if (last > 0)
  623.         LineDefs = (LDPtr) ResizeFarMemory( LineDefs, (unsigned long) NumLineDefs * sizeof( struct LineDef));
  624.     else
  625.         LineDefs = (LDPtr) GetFarMemory( sizeof( struct LineDef));
  626.     if (copyfrom >= 0) {
  627.         LineDefs[ last].start = LineDefs[ copyfrom].start;
  628.         LineDefs[ last].end = LineDefs[ copyfrom].end;
  629.         LineDefs[ last].flags = LineDefs[ copyfrom].flags;
  630.         LineDefs[ last].type = LineDefs[ copyfrom].type;
  631.         LineDefs[ last].tag = LineDefs[ copyfrom].tag;
  632.     }
  633.     else {
  634.         LineDefs[ last].start = 0;
  635.         LineDefs[ last].end = NumVertexes - 1;
  636.         LineDefs[ last].flags = 1;
  637.         LineDefs[ last].type = 0;
  638.         LineDefs[ last].tag = 0;
  639.     }
  640.     LineDefs[ last].sidedef1 = -1;
  641.     LineDefs[ last].sidedef2 = -1;
  642.     break;
  643.     case OBJ_SIDEDEFS:
  644.     /* SideDefs are added from the LineDefs menu, so "copyfrom" should always be -1.  But I test it anyway. */
  645.     last = NumSideDefs++;
  646.     if (last > 0)
  647.         SideDefs = (SDPtr) ResizeFarMemory( SideDefs, (unsigned long) NumSideDefs * sizeof( struct SideDef));
  648.     else
  649.         SideDefs = (SDPtr) GetFarMemory( sizeof( struct SideDef));
  650.     if (copyfrom >= 0) {
  651.         SideDefs[ last].xoff = SideDefs[ copyfrom].xoff;
  652.         SideDefs[ last].yoff = SideDefs[ copyfrom].yoff;
  653.         strncpy( SideDefs[ last].tex1, SideDefs[ copyfrom].tex1, 8);
  654.         strncpy( SideDefs[ last].tex2, SideDefs[ copyfrom].tex2, 8);
  655.         strncpy( SideDefs[ last].tex3, SideDefs[ copyfrom].tex3, 8);
  656.         SideDefs[ last].sector = SideDefs[ copyfrom].sector;
  657.     }
  658.     else {
  659.         SideDefs[ last].xoff = 0;
  660.         SideDefs[ last].yoff = 0;
  661.         strcpy( SideDefs[ last].tex1, "-");
  662.         strcpy( SideDefs[ last].tex2, "-");
  663.         strcpy( SideDefs[ last].tex3, DefaultWallTexture);
  664.         SideDefs[ last].sector = NumSectors - 1;
  665.     }
  666.     MadeMapChanges = TRUE;
  667.     break;
  668.     case OBJ_SECTORS:
  669.     last = NumSectors++;
  670.     if (last > 0)
  671.         Sectors = (SPtr) ResizeFarMemory( Sectors, (unsigned long) NumSectors * sizeof( struct Sector));
  672.     else
  673.         Sectors = (SPtr) GetFarMemory( sizeof( struct Sector));
  674.     if (copyfrom >= 0) {
  675.         Sectors[ last].floorh = Sectors[ copyfrom].floorh;
  676.         Sectors[ last].ceilh = Sectors[ copyfrom].ceilh;
  677.         strncpy( Sectors[ last].floort, Sectors[ copyfrom].floort, 8);
  678.         strncpy( Sectors[ last].ceilt, Sectors[ copyfrom].ceilt, 8);
  679.         Sectors[ last].light = Sectors[ copyfrom].light;
  680.         Sectors[ last].special = Sectors[ copyfrom].special;
  681.         Sectors[ last].tag = Sectors[ copyfrom].tag;
  682.     }
  683.     else {
  684.         Sectors[ last].floorh = DefaultFloorHeight;
  685.         Sectors[ last].ceilh = DefaultCeilingHeight;
  686.         strncpy( Sectors[ last].floort, DefaultFloorTexture, 8);
  687.         strncpy( Sectors[ last].ceilt, DefaultCeilingTexture, 8);
  688.         Sectors[ last].light = 255;
  689.         Sectors[ last].special = 0;
  690.         Sectors[ last].tag = 0;
  691.     }
  692.     break;
  693.     default:
  694.     Beep();
  695.     }
  696. }
  697.  
  698.  
  699.  
  700. /*
  701.    check if a (part of a) LineDef is inside a given block
  702.    */
  703.  
  704. Bool IsLineDefInside( BCINT ldnum, BCINT x0, BCINT y0, BCINT x1, BCINT y1) /* SWAP - needs Vertexes & LineDefs */
  705. {
  706.     BCINT lx0 = Vertexes[ LineDefs[ ldnum].start].x;
  707.     BCINT ly0 = Vertexes[ LineDefs[ ldnum].start].y;
  708.     BCINT lx1 = Vertexes[ LineDefs[ ldnum].end].x;
  709.     BCINT ly1 = Vertexes[ LineDefs[ ldnum].end].y;
  710.     BCINT i;
  711.     
  712.     /* do you like mathematics? */
  713.     if (lx0 >= x0 && lx0 <= x1 && ly0 >= y0 && ly0 <= y1)
  714.     return TRUE; /* the LineDef start is entirely inside the square */
  715.     if (lx1 >= x0 && lx1 <= x1 && ly1 >= y0 && ly1 <= y1)
  716.     return TRUE; /* the LineDef end is entirely inside the square */
  717.     if ((ly0 > y0) != (ly1 > y0)) {
  718.     i = lx0 + (BCINT) ( (long) (y0 - ly0) * (long) (lx1 - lx0) / (long) (ly1 - ly0));
  719.     if (i >= x0 && i <= x1)
  720.         return TRUE; /* the LineDef crosses the y0 side (left) */
  721.     }
  722.     if ((ly0 > y1) != (ly1 > y1)) {
  723.     i = lx0 + (BCINT) ( (long) (y1 - ly0) * (long) (lx1 - lx0) / (long) (ly1 - ly0));
  724.     if (i >= x0 && i <= x1)
  725.         return TRUE; /* the LineDef crosses the y1 side (right) */
  726.     }
  727.     if ((lx0 > x0) != (lx1 > x0)) {
  728.     i = ly0 + (BCINT) ( (long) (x0 - lx0) * (long) (ly1 - ly0) / (long) (lx1 - lx0));
  729.     if (i >= y0 && i <= y1)
  730.         return TRUE; /* the LineDef crosses the x0 side (down) */
  731.     }
  732.     if ((lx0 > x1) != (lx1 > x1)) {
  733.     i = ly0 + (BCINT) ( (long) (x1 - lx0) * (long) (ly1 - ly0) / (long) (lx1 - lx0));
  734.     if (i >= y0 && i <= y1)
  735.         return TRUE; /* the LineDef crosses the x1 side (up) */
  736.     }
  737.     return FALSE;        
  738. }
  739.  
  740.  
  741.  
  742. /*
  743.    get the Sector number of the SideDef opposite to this SideDef
  744.    (returns -1 if it cannot be found)
  745.    */
  746.  
  747. BCINT GetOppositeSector( BCINT ld1, Bool firstside) /* SWAP! */
  748. {
  749.     BCINT x0, y0, dx0, dy0;
  750.     BCINT x1, y1, dx1, dy1;
  751.     BCINT x2, y2, dx2, dy2;
  752.     BCINT ld2, dist;
  753.     BCINT bestld, bestdist, bestmdist;
  754.     
  755.     /* get the coords for this LineDef */
  756.     ObjectsNeeded( OBJ_LINEDEFS, OBJ_VERTEXES, 0);
  757.     x0  = Vertexes[ LineDefs[ ld1].start].x;
  758.     y0  = Vertexes[ LineDefs[ ld1].start].y;
  759.     dx0 = Vertexes[ LineDefs[ ld1].end].x - x0;
  760.     dy0 = Vertexes[ LineDefs[ ld1].end].y - y0;
  761.     
  762.     /* find the normal vector for this LineDef */
  763.     x1  = (dx0 + x0 + x0) / 2;
  764.     y1  = (dy0 + y0 + y0) / 2;
  765.     if (firstside == TRUE) {
  766.     dx1 = dy0;
  767.     dy1 = -dx0;
  768.     }
  769.     else {
  770.     dx1 = -dy0;
  771.     dy1 = dx0;
  772.     }
  773.     
  774.     bestld = -1;
  775.     /* use a parallel to an axis instead of the normal vector (faster method) */
  776.     if (abs( dy1) > abs( dx1)) {
  777.     if (dy1 > 0) {
  778.         /* get the nearest LineDef in that direction (increasing Y's: North) */
  779.         bestdist = 32767;
  780.         bestmdist = 32767;
  781.         for (ld2 = 0; ld2 < NumLineDefs; ld2++)
  782.         if (ld2 != ld1 && ((Vertexes[ LineDefs[ ld2].start].x > x1) != (Vertexes[ LineDefs[ ld2].end].x > x1))) {
  783.             x2  = Vertexes[ LineDefs[ ld2].start].x;
  784.             y2  = Vertexes[ LineDefs[ ld2].start].y;
  785.             dx2 = Vertexes[ LineDefs[ ld2].end].x - x2;
  786.             dy2 = Vertexes[ LineDefs[ ld2].end].y - y2;
  787.             dist = y2 + (BCINT) ((long) (x1 - x2) * (long) dy2 / (long) dx2);
  788.             if (dist > y1 && (dist < bestdist || (dist == bestdist && (y2 + dy2 / 2) < bestmdist))) {
  789.             bestld = ld2;
  790.             bestdist = dist;
  791.             bestmdist = y2 + dy2 / 2;
  792.             }
  793.         }
  794.     }
  795.     else {
  796.         /* get the nearest LineDef in that direction (decreasing Y's: South) */
  797.         bestdist = -32767;
  798.         bestmdist = -32767;
  799.         for (ld2 = 0; ld2 < NumLineDefs; ld2++)
  800.         if (ld2 != ld1 && ((Vertexes[ LineDefs[ ld2].start].x > x1) != (Vertexes[ LineDefs[ ld2].end].x > x1))) {
  801.             x2  = Vertexes[ LineDefs[ ld2].start].x;
  802.             y2  = Vertexes[ LineDefs[ ld2].start].y;
  803.             dx2 = Vertexes[ LineDefs[ ld2].end].x - x2;
  804.             dy2 = Vertexes[ LineDefs[ ld2].end].y - y2;
  805.             dist = y2 + (BCINT) ((long) (x1 - x2) * (long) dy2 / (long) dx2);
  806.             if (dist < y1 && (dist > bestdist || (dist == bestdist && (y2 + dy2 / 2) > bestmdist))) {
  807.             bestld = ld2;
  808.             bestdist = dist;
  809.             bestmdist = y2 + dy2 / 2;
  810.             }
  811.         }
  812.     }
  813.     }
  814.     else {
  815.     if (dx1 > 0) {
  816.         /* get the nearest LineDef in that direction (increasing X's: East) */
  817.         bestdist = 32767;
  818.         bestmdist = 32767;
  819.         for (ld2 = 0; ld2 < NumLineDefs; ld2++)
  820.         if (ld2 != ld1 && ((Vertexes[ LineDefs[ ld2].start].y > y1) != (Vertexes[ LineDefs[ ld2].end].y > y1))) {
  821.             x2  = Vertexes[ LineDefs[ ld2].start].x;
  822.             y2  = Vertexes[ LineDefs[ ld2].start].y;
  823.             dx2 = Vertexes[ LineDefs[ ld2].end].x - x2;
  824.             dy2 = Vertexes[ LineDefs[ ld2].end].y - y2;
  825.             dist = x2 + (BCINT) ((long) (y1 - y2) * (long) dx2 / (long) dy2);
  826.             if (dist > x1 && (dist < bestdist || (dist == bestdist && (x2 + dx2 / 2) < bestmdist))) {
  827.             bestld = ld2;
  828.             bestdist = dist;
  829.             bestmdist = x2 + dx2 / 2;
  830.             }
  831.         }
  832.     }
  833.     else {
  834.         /* get the nearest LineDef in that direction (decreasing X's: West) */
  835.         bestdist = -32767;
  836.         bestmdist = -32767;
  837.         for (ld2 = 0; ld2 < NumLineDefs; ld2++)
  838.         if (ld2 != ld1 && ((Vertexes[ LineDefs[ ld2].start].y > y1) != (Vertexes[ LineDefs[ ld2].end].y > y1))) {
  839.             x2  = Vertexes[ LineDefs[ ld2].start].x;
  840.             y2  = Vertexes[ LineDefs[ ld2].start].y;
  841.             dx2 = Vertexes[ LineDefs[ ld2].end].x - x2;
  842.             dy2 = Vertexes[ LineDefs[ ld2].end].y - y2;
  843.             dist = x2 + (BCINT) ((long) (y1 - y2) * (long) dx2 / (long) dy2);
  844.             if (dist < x1 && (dist > bestdist || (dist == bestdist && (x2 + dx2 / 2) > bestmdist))) {
  845.             bestld = ld2;
  846.             bestdist = dist;
  847.             bestmdist = x2 + dx2 / 2;
  848.             }
  849.         }
  850.     }
  851.     }
  852.     
  853.     /* no intersection: the LineDef was pointing outwards! */
  854.     if (bestld < 0)
  855.     return -1;
  856.     
  857.     /* now look if this LineDef has a SideDef bound to one sector */
  858.     if (abs( dy1) > abs( dx1)) {
  859.     if ((Vertexes[ LineDefs[ bestld].start].x < Vertexes[ LineDefs[ bestld].end].x) == (dy1 > 0))
  860.         x0 = LineDefs[ bestld].sidedef1;
  861.     else
  862.         x0 = LineDefs[ bestld].sidedef2;
  863.     }
  864.     else {
  865.     if ((Vertexes[ LineDefs[ bestld].start].y < Vertexes[ LineDefs[ bestld].end].y) != (dx1 > 0))
  866.         x0 = LineDefs[ bestld].sidedef1;
  867.     else
  868.         x0 = LineDefs[ bestld].sidedef2;
  869.     }
  870.     
  871.     /* there is no SideDef on this side of the LineDef! */
  872.     if (x0 < 0)
  873.     return -1;
  874.     
  875.     /* OK, we got it -- return the Sector number */
  876.     ObjectsNeeded( OBJ_SIDEDEFS, 0);
  877.     return SideDefs[ x0].sector;
  878. }
  879.  
  880.  
  881.  
  882. /*
  883.    copy a group of objects to a new position
  884.    */
  885.  
  886. void CopyObjects( BCINT objtype, SelPtr obj) /* SWAP! */
  887. {
  888.     BCINT        n, m;
  889.     SelPtr     cur;
  890.     SelPtr     list1, list2;
  891.     SelPtr     ref1, ref2;
  892.     
  893.     if (obj == NULL)
  894.     return;
  895.     ObjectsNeeded( objtype, 0);
  896.     /* copy the object(s) */
  897.     switch (objtype) {
  898.     case OBJ_THINGS:
  899.     for (cur = obj; cur; cur = cur->next) {
  900.         InsertObject( OBJ_THINGS, cur->objnum, Things[ cur->objnum].xpos, Things[ cur->objnum].ypos);
  901.         cur->objnum = NumThings - 1;
  902.     }
  903.     MadeChanges = TRUE;
  904.     break;
  905.     
  906.     case OBJ_VERTEXES:
  907.     for (cur = obj; cur; cur = cur->next) {
  908.         InsertObject( OBJ_VERTEXES, cur->objnum, Vertexes[ cur->objnum].x, Vertexes[ cur->objnum].y);
  909.         cur->objnum = NumVertexes - 1;
  910.     }
  911.     MadeChanges = TRUE;
  912.     MadeMapChanges = TRUE;
  913.     break;
  914.     
  915.     case OBJ_LINEDEFS:
  916.     list1 = NULL;
  917.     list2 = NULL;
  918.     /* create the LineDefs */
  919.     for (cur = obj; cur; cur = cur->next) {
  920.         InsertObject( OBJ_LINEDEFS, cur->objnum, 0, 0);
  921.         cur->objnum = NumLineDefs - 1;
  922.         if (!IsSelected( list1, LineDefs[ cur->objnum].start)) {
  923.         SelectObject( &list1, LineDefs[ cur->objnum].start);
  924.         SelectObject( &list2, LineDefs[ cur->objnum].start);
  925.         }
  926.         if (!IsSelected( list1, LineDefs[ cur->objnum].end)) {
  927.         SelectObject( &list1, LineDefs[ cur->objnum].end);
  928.         SelectObject( &list2, LineDefs[ cur->objnum].end);
  929.         }
  930.     }
  931.     /* create the Vertices */
  932.     CopyObjects( OBJ_VERTEXES, list2);
  933.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  934.     /* update the references to the Vertexes */
  935.     for (ref1 = list1, ref2 = list2; ref1 && ref2; ref1 = ref1->next, ref2 = ref2->next) {
  936.         for (cur = obj; cur; cur = cur->next) {
  937.         if (ref1->objnum == LineDefs[ cur->objnum].start)
  938.             LineDefs[ cur->objnum].start = ref2->objnum;
  939.         if (ref1->objnum == LineDefs[ cur->objnum].end)
  940.             LineDefs[ cur->objnum].end = ref2->objnum;
  941.         }
  942.     }
  943.     ForgetSelection( &list1);
  944.     ForgetSelection( &list2);
  945.     break;
  946.     
  947.     case OBJ_SECTORS:
  948.     ObjectsNeeded( OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
  949.     list1 = NULL;
  950.     list2 = NULL;
  951.     /* create the LineDefs (and Vertices) */
  952.     for (cur = obj; cur; cur = cur->next) {
  953.         for (n = 0; n < NumLineDefs; n++)
  954.         if ( (((m = LineDefs[ n].sidedef1) >= 0 && SideDefs[ m].sector == cur->objnum)
  955.               || ((m = LineDefs[ n].sidedef2) >= 0 && SideDefs[ m].sector == cur->objnum))
  956.             && ! IsSelected( list1, n)) {
  957.             SelectObject( &list1, n);
  958.             SelectObject( &list2, n);
  959.         }
  960.     }
  961.     CopyObjects( OBJ_LINEDEFS, list2);
  962.     /* create the SideDefs */
  963.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  964.     for (ref1 = list1, ref2 = list2; ref1 && ref2; ref1 = ref1->next, ref2 = ref2->next) {
  965.         if ((n = LineDefs[ ref1->objnum].sidedef1) >= 0) {
  966.         InsertObject( OBJ_SIDEDEFS, n, 0, 0);
  967.         n = NumSideDefs - 1;
  968.         ObjectsNeeded( OBJ_LINEDEFS, 0);
  969.         LineDefs[ ref2->objnum].sidedef1 = n;
  970.         }
  971.         if ((m = LineDefs[ ref1->objnum].sidedef2) >= 0) {
  972.         InsertObject( OBJ_SIDEDEFS, m, 0, 0);
  973.         m = NumSideDefs - 1;
  974.         ObjectsNeeded( OBJ_LINEDEFS, 0);
  975.         LineDefs[ ref2->objnum].sidedef2 = m;
  976.         }
  977.         ref1->objnum = n;
  978.         ref2->objnum = m;
  979.     }
  980.     /* create the Sectors */
  981.     for (cur = obj; cur; cur = cur->next) {
  982.         InsertObject( OBJ_SECTORS, cur->objnum, 0, 0);
  983.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  984.         for (ref1 = list1, ref2 = list2; ref1 && ref2; ref1 = ref1->next, ref2 = ref2->next) {
  985.         if (ref1->objnum >= 0 && SideDefs[ ref1->objnum].sector == cur->objnum)
  986.             SideDefs[ ref1->objnum].sector = NumSectors - 1;
  987.         if (ref2->objnum >= 0 && SideDefs[ ref2->objnum].sector == cur->objnum)
  988.             SideDefs[ ref2->objnum].sector = NumSectors - 1;
  989.         }
  990.         cur->objnum = NumSectors - 1;
  991.     }
  992.     ForgetSelection( &list1);
  993.     ForgetSelection( &list2);
  994.     break;
  995.     }
  996. }
  997.  
  998.  
  999.  
  1000. /*
  1001.    move a group of objects to a new position
  1002.    (must be called with obj = NULL before moving the objects)
  1003.    */
  1004.  
  1005. Bool MoveObjectsToCoords( BCINT objtype, SelPtr obj, BCINT newx, BCINT newy, BCINT grid) /* SWAP! */
  1006. {
  1007.     BCINT        n, m;
  1008.     BCINT        dx, dy;
  1009.     SelPtr     cur, vertices;
  1010.     static BCINT refx, refy; /* previous position */
  1011.     
  1012.     ObjectsNeeded( objtype, 0);
  1013.     if (grid > 0) {
  1014.     newx = (newx + grid / 2) & ~(grid - 1);
  1015.     newy = (newy + grid / 2) & ~(grid - 1);
  1016.     }
  1017.     
  1018.     /* only update the reference point? */
  1019.     if (obj == NULL) {
  1020.     refx = newx;
  1021.     refy = newy;
  1022.     return TRUE;
  1023.     }
  1024.     /* compute the displacement */
  1025.     dx = newx - refx;
  1026.     dy = newy - refy;
  1027.     /* nothing to do? */
  1028.     if (dx == 0 && dy == 0)
  1029.     return FALSE;
  1030.     
  1031.     /* move the object(s) */
  1032.     switch (objtype) {
  1033.     case OBJ_THINGS:
  1034.     for (cur = obj; cur; cur = cur->next) {
  1035.         Things[ cur->objnum].xpos += dx;
  1036.         Things[ cur->objnum].ypos += dy;
  1037.     }
  1038.     refx = newx;
  1039.     refy = newy;
  1040.     MadeChanges = TRUE;
  1041.     break;
  1042.     case OBJ_VERTEXES:
  1043.     for (cur = obj; cur; cur = cur->next) {
  1044.         Vertexes[ cur->objnum].x += dx;
  1045.         Vertexes[ cur->objnum].y += dy;
  1046.     }
  1047.     refx = newx;
  1048.     refy = newy;
  1049.     MadeChanges = TRUE;
  1050.     MadeMapChanges = TRUE;
  1051.     break;
  1052.     case OBJ_LINEDEFS:
  1053.     vertices = NULL;
  1054.     for (cur = obj; cur; cur = cur->next) {
  1055.         if (!IsSelected( vertices, LineDefs[ cur->objnum].start))
  1056.         SelectObject( &vertices, LineDefs[ cur->objnum].start);
  1057.         if (!IsSelected( vertices, LineDefs[ cur->objnum].end))
  1058.         SelectObject( &vertices, LineDefs[ cur->objnum].end);
  1059.     }
  1060.     MoveObjectsToCoords( OBJ_VERTEXES, vertices, newx, newy, grid);
  1061.     ForgetSelection( &vertices);
  1062.     break;
  1063.     case OBJ_SECTORS:
  1064.     ObjectsNeeded( OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
  1065.     vertices = NULL;
  1066.     for (cur = obj; cur; cur = cur->next) {
  1067.         for (n = 0; n < NumLineDefs; n++)
  1068.         if (((m = LineDefs[ n].sidedef1) >= 0 && SideDefs[ m].sector == cur->objnum)
  1069.             || ((m = LineDefs[ n].sidedef2) >= 0 && SideDefs[ m].sector == cur->objnum)) {
  1070.             if (!IsSelected( vertices, LineDefs[ n].start))
  1071.             SelectObject( &vertices, LineDefs[ n].start);
  1072.             if (!IsSelected( vertices, LineDefs[ n].end))
  1073.             SelectObject( &vertices, LineDefs[ n].end);
  1074.         }
  1075.     }
  1076.     MoveObjectsToCoords( OBJ_VERTEXES, vertices, newx, newy, grid);
  1077.     ForgetSelection( &vertices);
  1078.     break;
  1079.     }
  1080.     return TRUE;
  1081. }
  1082.  
  1083.  
  1084.  
  1085. /*
  1086.    get the coordinates (approx.) of an object
  1087.    */
  1088.  
  1089. void GetObjectCoords( BCINT objtype, BCINT objnum, BCINT *xpos, BCINT *ypos) /* SWAP! */
  1090. {
  1091.     BCINT  n, v1, v2, sd1, sd2;
  1092.     long accx, accy, num;
  1093.     
  1094.     switch (objtype) {
  1095.     case OBJ_THINGS:
  1096.     ObjectsNeeded( OBJ_THINGS, 0);
  1097.     *xpos = Things[ objnum].xpos;
  1098.     *ypos = Things[ objnum].ypos;
  1099.     break;
  1100.     case OBJ_VERTEXES:
  1101.     ObjectsNeeded( OBJ_VERTEXES, 0);
  1102.     *xpos = Vertexes[ objnum].x;
  1103.     *ypos = Vertexes[ objnum].y;
  1104.     break;
  1105.     case OBJ_LINEDEFS:
  1106.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  1107.     v1 = LineDefs[ objnum].start;
  1108.     v2 = LineDefs[ objnum].end;
  1109.     ObjectsNeeded( OBJ_VERTEXES, 0);
  1110.     *xpos = (Vertexes[ v1].x + Vertexes[ v2].x) / 2;
  1111.     *ypos = (Vertexes[ v1].y + Vertexes[ v2].y) / 2;
  1112.     break;
  1113.     case OBJ_SIDEDEFS:
  1114.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  1115.     for (n = 0; n < NumLineDefs; n++)
  1116.         if (LineDefs[ n].sidedef1 == objnum || LineDefs[ n].sidedef2 == objnum) {
  1117.         v1 = LineDefs[ n].start;
  1118.         v2 = LineDefs[ n].end;
  1119.         ObjectsNeeded( OBJ_VERTEXES, 0);
  1120.         *xpos = (Vertexes[ v1].x + Vertexes[ v2].x) / 2;
  1121.         *ypos = (Vertexes[ v1].y + Vertexes[ v2].y) / 2;
  1122.         return;
  1123.         }
  1124.     *xpos = (MapMinX + MapMaxX) / 2;
  1125.     *ypos = (MapMinY + MapMaxY) / 2;
  1126.     case OBJ_SECTORS:
  1127.     accx = 0L;
  1128.     accy = 0L;
  1129.     num = 0L;
  1130.     for (n = 0; n < NumLineDefs; n++) {
  1131.         ObjectsNeeded( OBJ_LINEDEFS, 0);
  1132.         sd1 = LineDefs[ n].sidedef1;
  1133.         sd2 = LineDefs[ n].sidedef2;
  1134.         v1 = LineDefs[ n].start;
  1135.         v2 = LineDefs[ n].end;
  1136.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1137.         if ((sd1 >= 0 && SideDefs[ sd1].sector == objnum) || (sd2 >= 0 && SideDefs[ sd2].sector == objnum)) {
  1138.         ObjectsNeeded( OBJ_VERTEXES, 0);
  1139.         /* if the Sector is closed, all Vertices will be counted twice */
  1140.         accx += (long) Vertexes[ v1].x;
  1141.         accy += (long) Vertexes[ v1].y;
  1142.         num++;
  1143.         accx += (long) Vertexes[ v2].x;
  1144.         accy += (long) Vertexes[ v2].y;
  1145.         num++;
  1146.         }
  1147.     }
  1148.     if (num > 0) {
  1149.         *xpos = (BCINT) ((accx + num / 2L) / num);
  1150.         *ypos = (BCINT) ((accy + num / 2L) / num);
  1151.     }
  1152.     else {
  1153.         *xpos = (MapMinX + MapMaxX) / 2;
  1154.         *ypos = (MapMinY + MapMaxY) / 2;
  1155.     }
  1156.     break;
  1157.     }
  1158. }
  1159.  
  1160.  
  1161.  
  1162. /*
  1163.    rotate and scale a group of objects around the center of gravity
  1164.    */
  1165.  
  1166. void RotateAndScaleObjects( BCINT objtype, SelPtr obj, double angle, double scale) /* SWAP! */
  1167. {
  1168.     BCINT    n, m;
  1169.     BCINT    dx, dy;
  1170.     BCINT    centerx, centery;
  1171.     long   accx, accy, num;
  1172.     SelPtr cur, vertices;
  1173.     
  1174.     if (obj == NULL)
  1175.     return;
  1176.     ObjectsNeeded( objtype, 0);
  1177.     
  1178.     switch (objtype) {
  1179.     case OBJ_THINGS:
  1180.     accx = 0L;
  1181.     accy = 0L;
  1182.     num = 0L;
  1183.     for (cur = obj; cur; cur = cur->next) {
  1184.         accx += (long) Things[ cur->objnum].xpos;
  1185.         accy += (long) Things[ cur->objnum].ypos;
  1186.         num++;
  1187.     }
  1188.     centerx = (BCINT) ((accx + num / 2L) / num);
  1189.     centery = (BCINT) ((accy + num / 2L) / num);
  1190.     for (cur = obj; cur; cur = cur->next) {
  1191.         dx = Things[ cur->objnum].xpos - centerx;
  1192.         dy = Things[ cur->objnum].ypos - centery;
  1193.         RotateAndScaleCoords( &dx, &dy, angle, scale);
  1194.         Things[ cur->objnum].xpos = centerx + dx;
  1195.         Things[ cur->objnum].ypos = centery + dy;
  1196.     }
  1197.     MadeChanges = TRUE;
  1198.     break;
  1199.     case OBJ_VERTEXES:
  1200.     accx = 0L;
  1201.     accy = 0L;
  1202.     num = 0L;
  1203.     for (cur = obj; cur; cur = cur->next) {
  1204.         accx += (long) Vertexes[ cur->objnum].x;
  1205.         accy += (long) Vertexes[ cur->objnum].y;
  1206.         num++;
  1207.     }
  1208.     centerx = (BCINT) ((accx + num / 2L) / num);
  1209.     centery = (BCINT) ((accy + num / 2L) / num);
  1210.     for (cur = obj; cur; cur = cur->next) {
  1211.         dx = Vertexes[ cur->objnum].x - centerx;
  1212.         dy = Vertexes[ cur->objnum].y - centery;
  1213.         RotateAndScaleCoords( &dx, &dy, angle, scale);
  1214.         Vertexes[ cur->objnum].x = (centerx + dx + 4) & ~7;
  1215.         Vertexes[ cur->objnum].y = (centery + dy + 4) & ~7;
  1216.     }
  1217.     MadeChanges = TRUE;
  1218.     MadeMapChanges = TRUE;
  1219.     break;
  1220.     case OBJ_LINEDEFS:
  1221.     vertices = NULL;
  1222.     for (cur = obj; cur; cur = cur->next) {
  1223.         if (!IsSelected( vertices, LineDefs[ cur->objnum].start))
  1224.         SelectObject( &vertices, LineDefs[ cur->objnum].start);
  1225.         if (!IsSelected( vertices, LineDefs[ cur->objnum].end))
  1226.         SelectObject( &vertices, LineDefs[ cur->objnum].end);
  1227.     }
  1228.     RotateAndScaleObjects( OBJ_VERTEXES, vertices, angle, scale);
  1229.     ForgetSelection( &vertices);
  1230.     break;
  1231.     case OBJ_SECTORS:
  1232.     ObjectsNeeded( OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
  1233.     vertices = NULL;
  1234.     for (cur = obj; cur; cur = cur->next) {
  1235.         for (n = 0; n < NumLineDefs; n++)
  1236.         if (((m = LineDefs[ n].sidedef1) >= 0 && SideDefs[ m].sector == cur->objnum)
  1237.             || ((m = LineDefs[ n].sidedef2) >= 0 && SideDefs[ m].sector == cur->objnum)) {
  1238.             if (!IsSelected( vertices, LineDefs[ n].start))
  1239.             SelectObject( &vertices, LineDefs[ n].start);
  1240.             if (!IsSelected( vertices, LineDefs[ n].end))
  1241.             SelectObject( &vertices, LineDefs[ n].end);
  1242.         }
  1243.     }
  1244.     RotateAndScaleObjects( OBJ_VERTEXES, vertices, angle, scale);
  1245.     ForgetSelection( &vertices);
  1246.     break;
  1247.     }
  1248. }
  1249.  
  1250.  
  1251.  
  1252. /*
  1253.    find a free tag number
  1254.    */
  1255.  
  1256. BCINT FindFreeTag() /* SWAP! */
  1257. {
  1258.     BCINT  tag, n;
  1259.     Bool ok;
  1260.     
  1261.     ObjectsNeeded( OBJ_LINEDEFS, OBJ_SECTORS, 0);
  1262.     tag = 1;
  1263.     ok = FALSE;
  1264.     while (! ok) {
  1265.     ok = TRUE;
  1266.     for (n = 0; n < NumLineDefs; n++)
  1267.         if (LineDefs[ n].tag == tag) {
  1268.         ok = FALSE;
  1269.         break;
  1270.         }
  1271.     if (ok)
  1272.         for (n = 0; n < NumSectors; n++)
  1273.         if (Sectors[ n].tag == tag) {
  1274.             ok = FALSE;
  1275.             break;
  1276.         }
  1277.     tag++;
  1278.     }
  1279.     return tag - 1;
  1280. }
  1281.  
  1282.  
  1283.  
  1284. /*
  1285.    flip one or several LineDefs
  1286.    */
  1287.  
  1288. void FlipLineDefs( SelPtr obj, Bool swapvertices) /* SWAP! */
  1289. {
  1290.     SelPtr cur;
  1291.     BCINT    tmp;
  1292.     
  1293.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  1294.     for (cur = obj; cur; cur = cur->next) {
  1295.     if (swapvertices) {
  1296.         /* swap starting and ending Vertices */
  1297.         tmp = LineDefs[ cur->objnum].end;
  1298.         LineDefs[ cur->objnum].end = LineDefs[ cur->objnum].start;
  1299.         LineDefs[ cur->objnum].start = tmp;
  1300.     }
  1301.     /* swap first and second SideDefs */
  1302.     tmp = LineDefs[ cur->objnum].sidedef1;
  1303.     LineDefs[ cur->objnum].sidedef1 = LineDefs[ cur->objnum].sidedef2;
  1304.     LineDefs[ cur->objnum].sidedef2 = tmp;
  1305.     }
  1306.     MadeChanges = TRUE;
  1307.     MadeMapChanges = TRUE;
  1308. }
  1309.  
  1310.  
  1311.  
  1312. /*
  1313.    delete a Vertex and join the two Linedefs
  1314.    */
  1315.  
  1316. void DeleteVerticesJoinLineDefs( SelPtr obj) /* SWAP! */
  1317. {
  1318.     BCINT    lstart, lend, l;
  1319.     SelPtr cur;
  1320.     char   msg[ 80];
  1321.     
  1322.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  1323.     while (obj != NULL) {
  1324.     cur = obj;
  1325.     obj = obj->next;
  1326.     lstart = -1;
  1327.     lend = -1;
  1328.     for (l = 0; l < NumLineDefs; l++) {
  1329.         if (LineDefs[ l].start == cur->objnum) {
  1330.         if (lstart == -1)
  1331.             lstart = l;
  1332.         else
  1333.             lstart = -2;
  1334.         }
  1335.         if (LineDefs[ l].end == cur->objnum) {
  1336.         if (lend == -1)
  1337.             lend = l;
  1338.         else
  1339.             lend = -2;
  1340.         }
  1341.     }
  1342.     if (lstart < 0 || lend < 0) {
  1343.         Beep();
  1344.         sprintf(msg, "Cannot delete Vertex #%d and join the LineDefs", cur->objnum);
  1345.         Notify( -1, -1, msg, "The Vertex must be the start of one LineDef and the end of another one");
  1346.         continue;
  1347.     }
  1348.     LineDefs[ lend].end = LineDefs[ lstart].end;
  1349.     DeleteObject( OBJ_LINEDEFS, lstart);
  1350.     DeleteObject( OBJ_VERTEXES, cur->objnum);
  1351.     MadeChanges = TRUE;
  1352.     MadeMapChanges = TRUE;
  1353.     }
  1354. }
  1355.  
  1356.  
  1357.  
  1358. /*
  1359.    merge several vertices into one
  1360.    */
  1361.  
  1362. void MergeVertices( SelPtr *list) /* SWAP! */
  1363. {
  1364.     BCINT    v, l;
  1365.     
  1366.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  1367.     v = (*list)->objnum;
  1368.     UnSelectObject( list, v);
  1369.     if (*list == NULL) {
  1370.     Beep();
  1371.     Notify( -1, -1, "You must select at least two vertices", NULL);
  1372.     return;
  1373.     }
  1374.     /* change the LineDefs starts & ends */
  1375.     for (l = 0; l < NumLineDefs; l++) {
  1376.     if (IsSelected( *list, LineDefs[ l].start)) {      
  1377.         /* don't change a LineDef that has both ends on the same spot */
  1378.         if (!IsSelected( *list, LineDefs[ l].end) && LineDefs[ l].end != v)
  1379.         LineDefs[ l].start = v;
  1380.     }
  1381.     else if (IsSelected( *list, LineDefs[ l].end)) {
  1382.         /* idem */
  1383.         if (LineDefs[ l].start != v)
  1384.         LineDefs[ l].end = v;
  1385.     }
  1386.     }
  1387.     /* delete the Vertices (and some LineDefs too) */
  1388.     DeleteObjects( OBJ_VERTEXES, list);
  1389.     MadeChanges = TRUE;
  1390.     MadeMapChanges = TRUE;
  1391. }
  1392.  
  1393.  
  1394.  
  1395. /*
  1396.    check if some vertices should be merged into one
  1397.    */
  1398.  
  1399. Bool AutoMergeVertices( SelPtr *list) /* SWAP! */
  1400. {
  1401.     SelPtr ref, cur;
  1402.     Bool   confirmed, redraw, flipped, mergedone, isldend;
  1403.     BCINT  v, refv, ld, sd, oldnumld;
  1404.     
  1405.     ObjectsNeeded( OBJ_VERTEXES, 0);
  1406.     confirmed = FALSE;
  1407.     redraw = FALSE;
  1408.     mergedone = FALSE;
  1409.     isldend = FALSE;
  1410.     ref = *list;
  1411.     while (ref) {
  1412.     refv = ref->objnum;
  1413.     ref = ref->next;
  1414.     /* check if there is a Vertex at the same position (same X and Y) */
  1415.     for (v = 0; v < NumVertexes; v++)
  1416.         if (v != refv && Vertexes[ refv].x == Vertexes[ v].x && Vertexes[ refv].y == Vertexes[ v].y) {
  1417.         redraw = TRUE;
  1418.         if (confirmed || Expert || Confirm( -1, -1, "Some Vertices occupy the same position", "Do you want to merge them into one?")) {
  1419.             /* don't ask for confirmation twice */
  1420.             confirmed = TRUE;
  1421.             /* merge the two vertices */
  1422.             mergedone = TRUE;
  1423.             cur = NULL;
  1424.             SelectObject( &cur, refv);
  1425.             SelectObject( &cur, v);
  1426.             MergeVertices( &cur);
  1427.             /* not useful but safer... */
  1428.             ObjectsNeeded( OBJ_VERTEXES, 0);
  1429.             /* update the references in the selection list */
  1430.             for (cur = *list; cur; cur = cur->next)
  1431.             if (cur->objnum > refv)
  1432.                 cur->objnum = cur->objnum - 1;
  1433.             if (v > refv)
  1434.             v--;
  1435.             /* the old Vertex has been deleted */
  1436.             UnSelectObject( list, refv);
  1437.             /* select the new Vertex instead */
  1438.             if (!IsSelected( *list, v))
  1439.             SelectObject( list, v);
  1440.             break;
  1441.         }
  1442.         else
  1443.             return redraw;
  1444.         }
  1445.     }
  1446.     confirmed = FALSE;
  1447.     ref = *list;
  1448.     while (ref) {
  1449.     refv = ref->objnum;
  1450.     ref = ref->next;
  1451.     oldnumld = NumLineDefs;
  1452.     /* check if this Vertex is on a LineDef */
  1453.     for (ld = 0; ld < oldnumld; ld++) {
  1454.         ObjectsNeeded( OBJ_VERTEXES, OBJ_LINEDEFS, 0);
  1455.         if (LineDefs[ ld].start == refv || LineDefs[ ld].end == refv) {
  1456.         /* one Vertex had a LineDef bound to it -- check it later */
  1457.         isldend = TRUE;
  1458.         }
  1459.         else if (IsLineDefInside( ld, Vertexes[ refv].x - 0, Vertexes[ refv].y - 0, Vertexes[ refv].x + 0, Vertexes[ refv].y + 0)) {
  1460.         redraw = TRUE;
  1461.         if (confirmed || Expert || Confirm( -1, -1, "Some Vertices are on a LineDef", "Do you want to split the LineDef there?")) {
  1462.             /* don't ask for confirmation twice */
  1463.             confirmed = TRUE;
  1464.             /* split the LineDef */
  1465.             mergedone = TRUE;
  1466.             InsertObject( OBJ_LINEDEFS, ld, 0, 0);
  1467.             LineDefs[ ld].end = refv;
  1468.             LineDefs[ NumLineDefs - 1].start = refv;
  1469.             sd = LineDefs[ ld].sidedef1;
  1470.             if (sd >= 0) {
  1471.             InsertObject( OBJ_SIDEDEFS, sd, 0, 0);
  1472.             ObjectsNeeded( OBJ_LINEDEFS, 0);
  1473.             LineDefs[ NumLineDefs - 1].sidedef1 = NumSideDefs - 1;
  1474.             }
  1475.             sd = LineDefs[ ld].sidedef2;
  1476.             if (sd >= 0) {
  1477.             InsertObject( OBJ_SIDEDEFS, sd, 0, 0);
  1478.             ObjectsNeeded( OBJ_LINEDEFS, 0);
  1479.             LineDefs[ NumLineDefs - 1].sidedef2 = NumSideDefs - 1;
  1480.             }
  1481.             MadeChanges = TRUE;
  1482.             MadeMapChanges = TRUE;
  1483.         }
  1484.         else
  1485.             return redraw;
  1486.         }
  1487.     }
  1488.     }
  1489.     /* don't continue if this isn't necessary */
  1490.     if (isldend == FALSE || mergedone == FALSE)
  1491.     return redraw;
  1492.     
  1493.     confirmed = FALSE;
  1494.     /* test if two LineDefs are at between the same pair of Vertices */
  1495.     for (v = 0; v < NumLineDefs - 1; v++)
  1496.     for (ld = v + 1; ld < NumLineDefs; ld++)
  1497.         if ((LineDefs[ v].start == LineDefs[ ld].start && LineDefs[ v].end == LineDefs[ ld].end)
  1498.         || (LineDefs[ v].start == LineDefs[ ld].end && LineDefs[ v].end == LineDefs[ ld].start)) {
  1499.         redraw = TRUE;
  1500.         if (confirmed || Expert || Confirm( -1, -1, "Some LineDefs are superimposed", "Do you want to merge them into one?")) {
  1501.             /* don't ask for confirmation twice */
  1502.             confirmed = TRUE;
  1503.             /* test if the LineDefs have the same orientation */
  1504.             if (LineDefs[ v].start == LineDefs[ ld].end)
  1505.             flipped = TRUE;
  1506.             else
  1507.             flipped = FALSE;
  1508.             /* merge the two LineDefs */
  1509.             if (LineDefs[ v].sidedef1 < 0) {
  1510.             if (flipped) {
  1511.                 LineDefs[ v].sidedef1 = LineDefs[ ld].sidedef2;
  1512.                 LineDefs[ ld].sidedef2 = -1;
  1513.             }
  1514.             else {
  1515.                 LineDefs[ v].sidedef1 = LineDefs[ ld].sidedef1;
  1516.                 LineDefs[ ld].sidedef1 = -1;
  1517.             }
  1518.             }
  1519.             if (LineDefs[ v].sidedef2 < 0) {
  1520.             if (flipped) {
  1521.                 LineDefs[ v].sidedef2 = LineDefs[ ld].sidedef1;
  1522.                 LineDefs[ ld].sidedef1 = -1;
  1523.             }
  1524.             else {
  1525.                 LineDefs[ v].sidedef2 = LineDefs[ ld].sidedef2;
  1526.                 LineDefs[ ld].sidedef2 = -1;
  1527.             }
  1528.             }
  1529.             if (LineDefs[ v].sidedef1 >= 0 && LineDefs[ v].sidedef2 >= 0 && (LineDefs[ v].flags & 0x04) == 0)
  1530.             LineDefs[ v].flags = 0x04;
  1531.             DeleteObject( OBJ_LINEDEFS, ld);
  1532.         }
  1533.         }
  1534.     return redraw;
  1535. }
  1536.  
  1537.  
  1538.  
  1539. /*
  1540.    split one or more LineDefs in two, adding new Vertices in the middle
  1541.    */
  1542.  
  1543. void SplitLineDefs( SelPtr obj) /* SWAP! */
  1544. {
  1545.     SelPtr cur;
  1546.     BCINT    vstart, vend, sd;
  1547.     
  1548.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  1549.     for (cur = obj; cur; cur = cur->next) {
  1550.     vstart = LineDefs[ cur->objnum].start;
  1551.     vend = LineDefs[ cur->objnum].end;
  1552.     InsertObject( OBJ_VERTEXES, -1, (Vertexes[ vstart].x + Vertexes[ vend].x) / 2, (Vertexes[ vstart].y + Vertexes[ vend].y) / 2);
  1553.     InsertObject( OBJ_LINEDEFS, cur->objnum, 0, 0);
  1554.     LineDefs[ cur->objnum].end = NumVertexes - 1;
  1555.     LineDefs[ NumLineDefs - 1].start = NumVertexes - 1;
  1556.     sd = LineDefs[ cur->objnum].sidedef1;
  1557.     if (sd >= 0) {
  1558.         InsertObject( OBJ_SIDEDEFS, sd, 0, 0);
  1559.         ObjectsNeeded( OBJ_LINEDEFS, 0);
  1560.         LineDefs[ NumLineDefs - 1].sidedef1 = NumSideDefs - 1;
  1561.     }
  1562.     sd = LineDefs[ cur->objnum].sidedef2;
  1563.     if (sd >= 0) {
  1564.         InsertObject( OBJ_SIDEDEFS, sd, 0, 0);
  1565.         ObjectsNeeded( OBJ_LINEDEFS, 0);
  1566.         LineDefs[ NumLineDefs - 1].sidedef2 = NumSideDefs - 1;
  1567.     }                
  1568.     }
  1569.     MadeChanges = TRUE;
  1570.     MadeMapChanges = TRUE;
  1571. }
  1572.  
  1573.  
  1574.  
  1575. /*
  1576.    split a Sector in two, adding a new LineDef between the two Vertices
  1577.    */
  1578.  
  1579. void SplitSector( BCINT vertex1, BCINT vertex2) /* SWAP! */
  1580. {
  1581.     SelPtr llist;
  1582.     BCINT    curv, s, l, sd;
  1583.     char   msg1[ 80], msg2[ 80];
  1584.     
  1585.     /* check if there is a Sector between the two Vertices (in the middle) */
  1586.     s = GetCurObject( OBJ_SECTORS, Vertexes[ vertex1].x, Vertexes[ vertex1].y, Vertexes[ vertex2].x, Vertexes[ vertex2].y);
  1587.     if (s < 0) {
  1588.     Beep();
  1589.     sprintf( msg1, "There is no Sector between Vertex #%d and Vertex #%d", vertex1, vertex2);
  1590.     Notify( -1, -1, msg1, NULL);
  1591.     return;
  1592.     }
  1593.     /* check if there is a closed path from vertex1 to vertex2, along the edge of the Sector s */
  1594.     ObjectsNeeded( OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
  1595.     llist = NULL;
  1596.     curv = vertex1;
  1597.     while (curv != vertex2) {
  1598.     for (l = 0; l < NumLineDefs; l++) {
  1599.         sd = LineDefs[ l].sidedef1;
  1600.         if (sd >= 0 && SideDefs[ sd].sector == s && LineDefs[ l].start == curv) {
  1601.         curv = LineDefs[ l].end;
  1602.         
  1603.         SelectObject( &llist, l);
  1604.         break;
  1605.         }
  1606.         sd = LineDefs[ l].sidedef2;
  1607.         if (sd >= 0 && SideDefs[ sd].sector == s && LineDefs[ l].end == curv) {
  1608.         curv = LineDefs[ l].start;
  1609.         SelectObject( &llist, l);
  1610.         break;
  1611.         }
  1612.     }
  1613.     if (l >= NumLineDefs) {
  1614.         Beep();
  1615.         sprintf( msg1, "Cannot find a closed path from Vertex #%d to Vertex #%d", vertex1, vertex2);
  1616.         if (curv == vertex1)
  1617.         sprintf( msg2, "There is no SideDef starting from Vertex #%d on Sector #%d", vertex1, s);
  1618.         else
  1619.         sprintf( msg2, "Check if Sector #%d is closed (cannot go past Vertex #%d)", s, curv);
  1620.         Notify( -1, -1, msg1, msg2);
  1621.         ForgetSelection( &llist);
  1622.         return;
  1623.     }
  1624.     if (curv == vertex1) {
  1625.         Beep();    
  1626.         sprintf( msg1, "Vertex #%d is not on the same Sector (#%d) as Vertex #%d", vertex2, s, vertex1);
  1627.         Notify( -1, -1, msg1, NULL);
  1628.         ForgetSelection( &llist);
  1629.         return;
  1630.     }
  1631.     }
  1632.     /* now, the list of LineDefs for the new Sector is in llist */
  1633.     
  1634.     /* add the new Sector, LineDef and SideDefs */
  1635.     InsertObject( OBJ_SECTORS, s, 0, 0);
  1636.     InsertObject( OBJ_LINEDEFS, -1, 0, 0);
  1637.     LineDefs[ NumLineDefs - 1].start = vertex1;
  1638.     LineDefs[ NumLineDefs - 1].end = vertex2;
  1639.     LineDefs[ NumLineDefs - 1].flags = 4;
  1640.     InsertObject( OBJ_SIDEDEFS, -1, 0, 0);
  1641.     SideDefs[ NumSideDefs - 1].sector = s;
  1642.     strncpy( SideDefs[ NumSideDefs - 1].tex3, "-", 8);
  1643.     InsertObject( OBJ_SIDEDEFS, -1, 0, 0);
  1644.     strncpy( SideDefs[ NumSideDefs - 1].tex3, "-", 8);
  1645.     ObjectsNeeded( OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
  1646.     LineDefs[ NumLineDefs - 1].sidedef1 = NumSideDefs - 2;
  1647.     LineDefs[ NumLineDefs - 1].sidedef2 = NumSideDefs - 1;
  1648.     
  1649.     /* bind all LineDefs in llist to the new Sector */
  1650.     while (llist) {
  1651.     sd = LineDefs[ llist->objnum].sidedef1;
  1652.     if (sd < 0 || SideDefs[ sd].sector != s)
  1653.         sd = LineDefs[ llist->objnum].sidedef2;
  1654.     SideDefs[ sd].sector = NumSectors - 1;
  1655.     UnSelectObject( &llist, llist->objnum);
  1656.     }
  1657.     
  1658.     
  1659.     /* second check... uselful for Sectors within Sectors */
  1660.     ObjectsNeeded( OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
  1661.     for (l = 0; l < NumLineDefs; l++) {
  1662.     sd = LineDefs[ l].sidedef1;
  1663.     if (sd >= 0 && SideDefs[ sd].sector == s) {
  1664.         curv = GetOppositeSector( l, TRUE);
  1665.         ObjectsNeeded( OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
  1666.         if (curv == NumSectors - 1)
  1667.         SideDefs[ sd].sector = NumSectors - 1;
  1668.     }
  1669.     sd = LineDefs[ l].sidedef2;
  1670.     if (sd >= 0 && SideDefs[ sd].sector == s) {
  1671.         curv = GetOppositeSector( l, FALSE);
  1672.         ObjectsNeeded( OBJ_LINEDEFS, OBJ_SIDEDEFS, 0);
  1673.         if (curv == NumSectors - 1)
  1674.         SideDefs[ sd].sector = NumSectors - 1;
  1675.     }
  1676.     }
  1677.     
  1678.     MadeChanges = TRUE;
  1679.     MadeMapChanges = TRUE;
  1680. }
  1681.  
  1682.  
  1683.  
  1684. /*
  1685.    split two LineDefs, then split the Sector and add a new LineDef between the new Vertices
  1686.    */
  1687.  
  1688. void SplitLineDefsAndSector( BCINT linedef1, BCINT linedef2) /* SWAP! */
  1689. {
  1690.     SelPtr llist;
  1691.     BCINT    s1, s2, s3, s4;
  1692.     char   msg[ 80];
  1693.     
  1694.     /* check if the two LineDefs are adjacent to the same Sector */
  1695.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  1696.     s1 = LineDefs[ linedef1].sidedef1;
  1697.     s2 = LineDefs[ linedef1].sidedef2;
  1698.     s3 = LineDefs[ linedef2].sidedef1;
  1699.     s4 = LineDefs[ linedef2].sidedef2;
  1700.     ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1701.     if (s1 >= 0)
  1702.     s1 = SideDefs[ s1].sector;
  1703.     if (s2 >= 0)
  1704.     s2 = SideDefs[ s2].sector;
  1705.     if (s3 >= 0)
  1706.     s3 = SideDefs[ s3].sector;
  1707.     if (s4 >= 0)
  1708.     s4 = SideDefs[ s4].sector;
  1709.     if ((s1 < 0 || (s1 != s3 && s1 != s4)) && (s2 < 0 || (s2 != s3 && s2 != s4))) {
  1710.     Beep();
  1711.     sprintf( msg, "LineDefs #%d and #%d are not adjacent to the same Sector", linedef1, linedef2);
  1712.     Notify( -1, -1, msg, NULL);
  1713.     return;
  1714.     }
  1715.     /* split the two LineDefs and create two new Vertices */
  1716.     llist = NULL;
  1717.     SelectObject( &llist, linedef1);
  1718.     SelectObject( &llist, linedef2);
  1719.     SplitLineDefs( llist);
  1720.     ForgetSelection( &llist);
  1721.     /* split the Sector and create a LineDef between the two Vertices */
  1722.     SplitSector( NumVertexes - 1, NumVertexes - 2);
  1723. }
  1724.  
  1725.  
  1726. /*
  1727.    merge two or more Sectors into one
  1728.    */
  1729.  
  1730. void MergeSectors( SelPtr *slist) /* SWAP! */
  1731. {
  1732.     SelPtr cur;
  1733.     BCINT    n, olds, news;
  1734.     
  1735.     /* save the first Sector number */
  1736.     news = (*slist)->objnum;
  1737.     UnSelectObject( slist, news);
  1738.     ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1739.     
  1740.     /* change all SideDefs references to the other Sectors */
  1741.     for (cur = *slist; cur; cur = cur->next) {
  1742.     olds = cur->objnum;
  1743.     for (n = 0; n < NumSideDefs; n++) {
  1744.         if (SideDefs[ n].sector == olds)
  1745.         SideDefs[ n].sector = news;
  1746.     }
  1747.     }
  1748.     
  1749.     /* delete the Sectors */
  1750.     DeleteObjects( OBJ_SECTORS, slist);
  1751.     
  1752.     /* the returned list contains only the first Sector */
  1753.     SelectObject( slist, news);
  1754. }
  1755.  
  1756.  
  1757.  
  1758. /*
  1759.    delete one or several two-sided LineDefs and join the two Sectors
  1760.    */
  1761.  
  1762. void DeleteLineDefsJoinSectors( SelPtr *ldlist) /* SWAP! */
  1763. {
  1764.     SelPtr cur, slist;
  1765.     BCINT  sd1, sd2, s1, s2;
  1766.     char   msg[ 80];
  1767.     
  1768.     /* first, do the tests for all LineDefs */
  1769.     for (cur = *ldlist; cur; cur = cur->next) {
  1770.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  1771.     sd1 = LineDefs[ cur->objnum].sidedef1;
  1772.     sd2 = LineDefs[ cur->objnum].sidedef2;
  1773.     if (sd1 < 0 || sd2 < 0) {
  1774.         Beep();
  1775.         sprintf( msg, "ERROR: LineDef #%d has only one side", cur->objnum);
  1776.         Notify( -1, -1, msg, NULL);
  1777.         return;
  1778.     }
  1779.     ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1780.     s1 = SideDefs[ sd1].sector;
  1781.     s2 = SideDefs[ sd2].sector;
  1782.     if (s1 < 0 || s2 < 0) {
  1783.         Beep();
  1784.         sprintf( msg, "ERROR: LineDef #%d has two sides, but one", cur->objnum);
  1785.         Notify( -1, -1, msg, "side is not bound to any Sector");
  1786.         return;
  1787.     }
  1788.     }
  1789.     
  1790.     /* then join the Sectors and delete the LineDefs */
  1791.     for (cur = *ldlist; cur; cur = cur->next) {
  1792.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  1793.     sd1 = LineDefs[ cur->objnum].sidedef1;
  1794.     sd2 = LineDefs[ cur->objnum].sidedef2;
  1795.     ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1796.     s1 = SideDefs[ sd1].sector;
  1797.     s2 = SideDefs[ sd2].sector;
  1798.     slist = NULL;
  1799.     SelectObject( &slist, s2);
  1800.     SelectObject( &slist, s1);
  1801.     MergeSectors( &slist);
  1802.     ForgetSelection( &slist);
  1803.     }
  1804.     DeleteObjects( OBJ_LINEDEFS, ldlist);
  1805. }
  1806.  
  1807.  
  1808.  
  1809.  
  1810. /*
  1811.    turn a Sector into a door: change the LineDefs and SideDefs
  1812.    */
  1813.  
  1814. void MakeDoorFromSector( BCINT sector) /* SWAP! */
  1815. {
  1816.     BCINT    sd1, sd2;
  1817.     BCINT    n, s;
  1818.     SelPtr ldok, ldflip, ld1s;
  1819.     
  1820.     ldok = NULL;
  1821.     ldflip = NULL;
  1822.     ld1s = NULL;
  1823.     s = 0;
  1824.     /* build lists of LineDefs that border the Sector */
  1825.     for (n = 0; n < NumLineDefs; n++) {
  1826.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  1827.     sd1 = LineDefs[ n].sidedef1;
  1828.     sd2 = LineDefs[ n].sidedef2;
  1829.     if (sd1 >= 0 && sd2 >= 0) {
  1830.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1831.         if (SideDefs[ sd2].sector == sector) {
  1832.         SelectObject( &ldok, n); /* already ok */
  1833.         s++;
  1834.         }
  1835.         if (SideDefs[ sd1].sector == sector) {
  1836.         SelectObject( &ldflip, n); /* must be flipped */
  1837.         s++;
  1838.         }
  1839.     }
  1840.     else if (sd1 >= 0 && sd2 < 0) {
  1841.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1842.         if (SideDefs[ sd1].sector == sector)
  1843.         SelectObject( &ld1s, n); /* wall (one-sided) */
  1844.     }
  1845.     }
  1846.     /* a normal door has two sides... */
  1847.     if (s < 2) {
  1848.     Beep();
  1849.     Notify( -1, -1, "The door must be connected to two other Sectors.", NULL);
  1850.     ForgetSelection( &ldok);
  1851.     ForgetSelection( &ldflip);
  1852.     ForgetSelection( &ld1s);
  1853.     return;
  1854.     }
  1855.     if ((s > 2) && !(Expert || Confirm( -1, -1, "The door will have more than two sides.", "Do you still want to create it?"))) {
  1856.     ForgetSelection( &ldok);
  1857.     ForgetSelection( &ldflip);
  1858.     ForgetSelection( &ld1s);
  1859.     return;
  1860.     }
  1861.     /* flip the LineDefs that have the wrong orientation */
  1862.     if (ldflip != NULL)
  1863.     FlipLineDefs( ldflip, TRUE);
  1864.     /* merge the two selection lists */
  1865.     while (ldflip != NULL) {
  1866.     if (!IsSelected( ldok, ldflip->objnum))
  1867.         SelectObject( &ldok, ldflip->objnum);
  1868.     UnSelectObject( &ldflip, ldflip->objnum);
  1869.     }
  1870.     /* change the LineDefs and SideDefs */
  1871.     while (ldok != NULL) {
  1872.     /* give the "normal door" type and flags to the LineDef */
  1873.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  1874.     n = ldok->objnum;
  1875.     LineDefs[ n].type = 1;
  1876.     LineDefs[ n].flags = 0x04;
  1877.     sd1 = LineDefs[ n].sidedef1;
  1878.     sd2 = LineDefs[ n].sidedef2;
  1879.     /* adjust the textures for the SideDefs */
  1880.     ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1881.     if (strncmp( SideDefs[ sd1].tex3, "-", 8)) {
  1882.         if (!strncmp( SideDefs[ sd1].tex1, "-", 8))
  1883.         strncpy( SideDefs[ sd1].tex1, SideDefs[ sd1].tex3, 8);
  1884.         strncpy( SideDefs[ sd1].tex3, "-", 8);
  1885.     }
  1886.     if (!strncmp( SideDefs[ sd1].tex1, "-", 8))
  1887.         strncpy( SideDefs[ sd1].tex1, DefaultDoorTexture, 8);
  1888.     strncpy( SideDefs[ sd2].tex3, "-", 8);
  1889.     UnSelectObject( &ldok, n);
  1890.     }
  1891.     while (ld1s != NULL) {
  1892.     /* give the "door side" flags to the LineDef */
  1893.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  1894.     n = ld1s->objnum;
  1895.     LineDefs[ n].flags = 0x11;
  1896.     sd1 = LineDefs[ n].sidedef1;
  1897.     /* adjust the textures for the SideDef */
  1898.     ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1899.     /* if (!strncmp( SideDefs[ sd1].tex3, "-", 8)) */
  1900.     strncpy( SideDefs[ sd1].tex3, DefaultDoorTrack, 8);
  1901.     strncpy( SideDefs[ sd1].tex1, "-", 8);
  1902.     strncpy( SideDefs[ sd1].tex2, "-", 8);
  1903.     UnSelectObject( &ld1s, n);
  1904.     }
  1905.     /* adjust the ceiling height */
  1906.     ObjectsNeeded( OBJ_SECTORS, 0);
  1907.     Sectors[ sector].ceilh = Sectors[ sector].floorh;
  1908. }
  1909.  
  1910.  
  1911.  
  1912. /*
  1913.    turn a Sector into a lift: change the LineDefs and SideDefs
  1914.    */
  1915.  
  1916. void MakeLiftFromSector( BCINT sector) /* SWAP! */
  1917. {
  1918.     BCINT    sd1, sd2;
  1919.     BCINT    n, s, tag;
  1920.     SelPtr ldok, ldflip, ld1s;
  1921.     SelPtr sect, curs;
  1922.     BCINT    minh, maxh;
  1923.     
  1924.     ldok = NULL;
  1925.     ldflip = NULL;
  1926.     ld1s = NULL;
  1927.     sect = NULL;
  1928.     /* build lists of LineDefs that border the Sector */
  1929.     for (n = 0; n < NumLineDefs; n++) {
  1930.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  1931.     sd1 = LineDefs[ n].sidedef1;
  1932.     sd2 = LineDefs[ n].sidedef2;
  1933.     if (sd1 >= 0 && sd2 >= 0) {
  1934.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1935.         if (SideDefs[ sd2].sector == sector) {
  1936.         SelectObject( &ldok, n); /* already ok */
  1937.         s = SideDefs[ sd1].sector;
  1938.         if (s != sector && !IsSelected( sect, s))
  1939.             SelectObject( §, s);
  1940.         }
  1941.         if (SideDefs[ sd1].sector == sector) {
  1942.         SelectObject( &ldflip, n); /* will be flipped */
  1943.         s = SideDefs[ sd2].sector;
  1944.         if (s != sector && !IsSelected( sect, s))
  1945.             SelectObject( §, s);
  1946.         }
  1947.     }
  1948.     else if (sd1 >= 0 && sd2 < 0) {
  1949.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  1950.         if (SideDefs[ sd1].sector == sector)
  1951.         SelectObject( &ld1s, n); /* wall (one-sided) */
  1952.     }
  1953.     }
  1954.     /* there must be a way to go on the lift... */
  1955.     if (sect == NULL) {
  1956.     Beep();
  1957.     Notify( -1, -1, "The lift must be connected to at least one other Sector.", NULL);
  1958.     ForgetSelection( &ldok);
  1959.     ForgetSelection( &ldflip);
  1960.     ForgetSelection( &ld1s);
  1961.     return;
  1962.     }
  1963.     /* flip the LineDefs that have the wrong orientation */
  1964.     if (ldflip != NULL)
  1965.     FlipLineDefs( ldflip, TRUE);
  1966.     /* merge the two selection lists */
  1967.     while (ldflip != NULL) {
  1968.     if (!IsSelected( ldok, ldflip->objnum))
  1969.         SelectObject( &ldok, ldflip->objnum);
  1970.     UnSelectObject( &ldflip, ldflip->objnum);
  1971.     }
  1972.     /* find a free tag number */
  1973.     tag = FindFreeTag();
  1974.     /* find the minimum altitude */
  1975.     ObjectsNeeded( OBJ_SECTORS, 0);
  1976.     minh = 32767;
  1977.     maxh = -32767;
  1978.     for (curs = sect; curs; curs = curs->next) {
  1979.     if (Sectors[ curs->objnum].floorh < minh)
  1980.         minh = Sectors[ curs->objnum].floorh;
  1981.     if (Sectors[ curs->objnum].floorh > maxh)
  1982.         maxh = Sectors[ curs->objnum].floorh;
  1983.     }
  1984.     ForgetSelection( §);
  1985.     
  1986.     /* change the Sector altitude if necessary */
  1987.     if (Sectors[ sector].floorh < maxh)
  1988.     Sectors[ sector].floorh = maxh;
  1989.     
  1990.     /* change the lift's ceiling height if necessary */
  1991.     if (Sectors[ sector].ceilh < maxh + 56)
  1992.     Sectors[ sector].ceilh = maxh + 56;     
  1993.     
  1994.     /* assign the new tag number to the lift */
  1995.     Sectors[ sector].tag = tag;
  1996.     
  1997.     /* change the LineDefs and SideDefs */
  1998.     while (ldok != NULL) {
  1999.     /* give the "lower lift" type and flags to the LineDef */
  2000.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  2001.     n = ldok->objnum;
  2002.     LineDefs[ n].type = 62; /* lower lift (switch) */
  2003.     LineDefs[ n].flags = 0x04;
  2004.     LineDefs[ n].tag = tag;
  2005.     sd1 = LineDefs[ n].sidedef1;
  2006.     sd2 = LineDefs[ n].sidedef2;
  2007.     /* adjust the textures for the SideDefs visible from the outside */
  2008.     ObjectsNeeded( OBJ_SIDEDEFS, 0);
  2009.     if (strncmp( SideDefs[ sd1].tex3, "-", 8)) {
  2010.         if (!strncmp( SideDefs[ sd1].tex2, "-", 8))
  2011.         strncpy( SideDefs[ sd1].tex2, SideDefs[ sd1].tex3, 8);
  2012.         strncpy( SideDefs[ sd1].tex3, "-", 8);
  2013.     }
  2014.     if (!strncmp( SideDefs[ sd1].tex2, "-", 8))
  2015.         strncpy( SideDefs[ sd1].tex2, "SHAWN2", 8);
  2016.     /* adjust the textures for the SideDef visible from the lift */
  2017.     strncpy( SideDefs[ sd2].tex3, "-", 8);
  2018.     s = SideDefs[ sd1].sector;
  2019.     ObjectsNeeded( OBJ_SECTORS, 0);
  2020.     if (Sectors[ s].floorh > minh) {
  2021.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  2022.         if (strncmp( SideDefs[ sd2].tex3, "-", 8)) {
  2023.         if (!strncmp( SideDefs[ sd2].tex2, "-", 8))
  2024.             strncpy( SideDefs[ sd2].tex2, SideDefs[ sd1].tex3, 8);
  2025.         strncpy( SideDefs[ sd2].tex3, "-", 8);
  2026.         }
  2027.         if (!strncmp( SideDefs[ sd2].tex2, "-", 8))
  2028.         strncpy( SideDefs[ sd2].tex2, "SHAWN2", 8);
  2029.     }
  2030.     else {
  2031.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  2032.         strncpy( SideDefs[ sd2].tex2, "-", 8);
  2033.     }
  2034.     strncpy( SideDefs[ sd2].tex3, "-", 8);
  2035.     ObjectsNeeded( OBJ_SECTORS, 0);
  2036.     
  2037.     /* if the ceiling of the Sector is lower than that of the lift */
  2038.     if (Sectors[ s].ceilh < Sectors[ sector].ceilh) {
  2039.         ObjectsNeeded( OBJ_SIDEDEFS, 0);
  2040.         if (strncmp( SideDefs[ sd2].tex1, "-", 8))
  2041.         strncpy( SideDefs[ sd2].tex1, DefaultUpperTexture, 8);
  2042.     }
  2043.     ObjectsNeeded( OBJ_SECTORS, 0);
  2044.     
  2045.     /* if the floor of the Sector is above the lift */
  2046.     if (Sectors[ s].floorh >= Sectors[ sector].floorh) {
  2047.         ObjectsNeeded( OBJ_LINEDEFS, 0);
  2048.         LineDefs[ n].type = 88; /* lower lift (walk through) */
  2049.         /* flip it, just for fun */
  2050.         curs = NULL;
  2051.         SelectObject( &curs, n);
  2052.         FlipLineDefs( curs, TRUE);
  2053.         ForgetSelection( &curs);
  2054.     }
  2055.     /* done with this LineDef */
  2056.     UnSelectObject( &ldok, n);
  2057.     }
  2058.     while (ld1s != NULL) {
  2059.     /* these are the lift walls (one-sided) */
  2060.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  2061.     n = ld1s->objnum;
  2062.     LineDefs[ n].flags = 0x01;
  2063.     sd1 = LineDefs[ n].sidedef1;
  2064.     /* adjust the textures for the SideDef */
  2065.     ObjectsNeeded( OBJ_SIDEDEFS, 0);
  2066.     if (!strncmp( SideDefs[ sd1].tex3, "-", 8))
  2067.         strncpy( SideDefs[ sd1].tex3, DefaultWallTexture, 8);
  2068.     strncpy( SideDefs[ sd1].tex1, "-", 8);
  2069.     strncpy( SideDefs[ sd1].tex2, "-", 8);
  2070.     UnSelectObject( &ld1s, n);
  2071.     }
  2072. }
  2073.  
  2074.  
  2075.  
  2076. /*
  2077.    get the absolute height from which the textures are drawn
  2078.    */
  2079.  
  2080. BCINT GetTextureRefHeight( BCINT sidedef)
  2081. {
  2082.     BCINT l, sector;
  2083.     BCINT otherside = -1;
  2084.     
  2085.     /* find the SideDef on the other side of the LineDef, if any */
  2086.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  2087.     for (l = 0; l < NumLineDefs; l++) {
  2088.         if (LineDefs[ l].sidedef1 == sidedef) {
  2089.             otherside = LineDefs[ l].sidedef2;
  2090.             break;
  2091.         }
  2092.         if (LineDefs[ l].sidedef2 == sidedef) {
  2093.             otherside = LineDefs[ l].sidedef1;
  2094.             break;
  2095.         }
  2096.     }
  2097.     /* get the Sector number */
  2098.     ObjectsNeeded( OBJ_SIDEDEFS, 0);
  2099.     sector = SideDefs[ sidedef].sector;
  2100.     /* if the upper texture is displayed, then the reference
  2101.        is taken from the other Sector */
  2102.     if (otherside >= 0) {
  2103.         l = SideDefs[ otherside].sector;
  2104.         if (l > 0) {
  2105.             ObjectsNeeded( OBJ_SECTORS, 0);
  2106.             if (Sectors[ l].ceilh < Sectors[ sector].ceilh &&
  2107.                    Sectors[ l].ceilh > Sectors[ sector].floorh)
  2108.                 sector = l;
  2109.         }
  2110.     }
  2111.     /* return the altitude of the ceiling */
  2112.     ObjectsNeeded( OBJ_SECTORS, 0);
  2113.     if (sector >= 0)
  2114.         return Sectors[ sector].ceilh;
  2115.         /* textures are drawn from the ceiling down */
  2116.     else
  2117.         return 0; /* yuck! */
  2118. }
  2119.  
  2120.  
  2121.  
  2122. /*
  2123.    Align all textures for the given SideDefs
  2124. */
  2125. void AlignTexturesY( SelPtr *list, Bool NoChecking, Bool UseOffset)
  2126. {
  2127.     BCINT InitOffset, RefHeight = -1, offset;
  2128.     char TextureName[9] = "\0\0\0\0\0\0\0\0\0",
  2129.          PreviousTexture[9] = "\0\0\0\0\0\0\0\0\0";
  2130.     BCINT sidedef, side, linedef;
  2131.     Bool FirstTime = TRUE;
  2132.     BCINT v, vert1, vert2, PrevLinedef = -1;
  2133.     SelPtr ldlist, listhead;
  2134.     Texture *t_info;
  2135.  
  2136.     listhead = ldlist = rev_list(*list);
  2137.  
  2138.     while(ldlist) {
  2139.         linedef = ldlist->objnum;
  2140.  
  2141.         if(ldlist->next) {
  2142.             if((v = CommonVertex(linedef, ldlist->next->objnum)) == -1)
  2143.                 return;
  2144.             side = (v == LineDefs[linedef].end) ? 1 : 2;
  2145.             PrevLinedef = linedef;
  2146.         }
  2147.         else {
  2148.             if((v = CommonVertex(linedef, PrevLinedef)) == -1)
  2149.                 return;
  2150.             side = (v == LineDefs[linedef].start) ? 1 : 2;
  2151.         }
  2152.  
  2153.             
  2154.         if(side == 1)
  2155.             sidedef = LineDefs[linedef].sidedef1;
  2156.         else
  2157.             sidedef = LineDefs[linedef].sidedef2;
  2158.  
  2159.         if(sidedef == -1)
  2160.             goto next;
  2161.  
  2162.         vert1 = LineDefs[linedef].start;
  2163.         vert2 = LineDefs[linedef].end;
  2164.  
  2165.         if(strcmp(SideDefs[sidedef].tex3, "-")) {
  2166.             strncpy(TextureName, SideDefs[sidedef].tex3, 8);
  2167.             goto got_one;
  2168.         }
  2169.  
  2170.         if(strcmp(SideDefs[sidedef].tex1, "-")) {
  2171.             strncpy(TextureName, SideDefs[sidedef].tex1, 8);
  2172.             goto got_one;
  2173.         }
  2174.  
  2175.         if(strcmp(SideDefs[sidedef].tex2, "-")) {
  2176.             strncpy(TextureName, SideDefs[sidedef].tex2, 8);
  2177.             goto got_one;
  2178.         }
  2179.  
  2180.         goto next;
  2181.  
  2182. got_one:
  2183.  
  2184.         if (FirstTime) {
  2185.             FirstTime = FALSE;
  2186.             InitOffset = 0;
  2187.  
  2188.             /* ask for initial offset if UseOffset is true */
  2189.         
  2190.             if(UseOffset == TRUE) {
  2191.                 BCINT  x0, y0, key;   
  2192.                 char prompt[80]; 
  2193.  
  2194.                 if(UseMouse)
  2195.                     HideMousePointer();
  2196.  
  2197.                 sprintf(prompt, "Enter initial offset between 0 and 127");
  2198.  
  2199.                 x0 = (ScrMaxX - 25 - 8 * strlen(prompt)) / 2;
  2200.                 y0 = (ScrMaxY - 55) / 2;
  2201.  
  2202.                 DrawScreenBox3D( x0, y0, x0 + 25 + 8 * strlen( prompt), y0 + 55);
  2203.                 SetColor(WHITE);
  2204.                 DrawScreenText( x0 + 10, y0 + 8, prompt);
  2205.  
  2206.                 while (((key=InputInteger(x0+10, y0+28, &InitOffset, 0, 127)) & 0x00FF)!=0x000D
  2207.                             && (key & 0x00FF) != 0x001B)
  2208.                     Beep();
  2209.  
  2210.                 if (UseMouse)
  2211.                     ShowMousePointer();
  2212.             }
  2213.  
  2214.             RefHeight = GetTextureRefHeight(sidedef);
  2215.             SideDefs[sidedef].yoff = InitOffset;
  2216.  
  2217.             strncpy(PreviousTexture, TextureName, 8);
  2218.              goto next; 
  2219.         }
  2220.  
  2221.         if((strcmp(PreviousTexture, TextureName)) && !NoChecking) {
  2222.             RefHeight = GetTextureRefHeight(sidedef);
  2223.         }
  2224.         else {
  2225.             t_info = FindTexture(TextureName);
  2226.             offset = RefHeight + InitOffset - GetTextureRefHeight(sidedef);
  2227.  
  2228.             while(offset < 0)
  2229.                 offset += t_info->height;
  2230.  
  2231.             while(offset >= t_info->height)
  2232.                 offset -= t_info->height;
  2233.             
  2234.             SideDefs[sidedef].yoff = offset;
  2235.         }
  2236.  
  2237.         strncpy(PreviousTexture, TextureName, 8);
  2238.  
  2239. next:
  2240.         ldlist = (ldlist)->next;
  2241.     }
  2242.  
  2243.     delete_list(listhead);
  2244.     
  2245.     MadeChanges = TRUE;
  2246. }
  2247.  
  2248.  
  2249.  
  2250. /*
  2251.    SO: This function has been re-written from scratch.
  2252.    It now accepts 3 parameters:
  2253.    sdlist is the list of currently highlighted sidedefs.
  2254.    NoChecking is whether to keep the accumulated offset even when
  2255.            the texture changes from one sidedef to the next.
  2256.    UseOffset is whether or not to ask the user for an initial X offset,
  2257.            or to simply start at 0.
  2258.  
  2259.    sdlist is immediately converted to ldlist, a list of LINEDEFS
  2260.    currently highlighted. We then follow the chain of linedefs,
  2261.    and align the textures along the right-hand side, working out
  2262.    each step of the way whether it is the first or second sidedef.
  2263.  
  2264.    e.g.
  2265.  
  2266.    --ld1--> <--ld2-- --ld3-->  
  2267.  
  2268.    Selecting the linedefs in the order ld1, ld2, ld3 will align the first
  2269.    sidedefs of ld1 & ld3, and the second sidedef of ld2.
  2270.    To align the second sidedefs of ld3 & ld1, and the first sidedef of
  2271.    ld2, select them in the order ld3, ld2, ld1.
  2272.    */
  2273.  
  2274. void AlignTexturesX( SelPtr *list, Bool NoChecking, Bool UseOffset)
  2275. {
  2276.     BCINT InitOffset, CurrentOffset, PreviousOffset = 0;
  2277.     char TextureName[9] = "\0\0\0\0\0\0\0\0\0",
  2278.          PreviousTexture[9] = "\0\0\0\0\0\0\0\0\0";
  2279.     BCINT sidedef, side, linedef;
  2280.     BCINT TextureWidth, PreviousWidth = 0;
  2281.     Bool FirstTime = TRUE;
  2282.     BCINT v, vert1, vert2, PrevLinedef = -1;
  2283.     SelPtr ldlist, listhead;
  2284.     Texture *t_info;
  2285.  
  2286.     listhead = ldlist = rev_list(*list);
  2287.  
  2288.     while(ldlist) {
  2289.         linedef = ldlist->objnum;
  2290.  
  2291.         if(ldlist->next) {
  2292.             if((v = CommonVertex(linedef, ldlist->next->objnum)) == -1)
  2293.                 return;
  2294.             side = (v == LineDefs[linedef].end) ? 1 : 2;
  2295.             PrevLinedef = linedef;
  2296.         }
  2297.         else {
  2298.             if(PrevLinedef == -1)
  2299.                 return;
  2300.             if((v = CommonVertex(linedef, PrevLinedef)) == -1)
  2301.                 return;
  2302.             side = (v == LineDefs[linedef].start) ? 1 : 2;
  2303.         }
  2304.  
  2305.             
  2306.         if(side == 1)
  2307.             sidedef = LineDefs[linedef].sidedef1;
  2308.         else
  2309.             sidedef = LineDefs[linedef].sidedef2;
  2310.  
  2311.         if(sidedef == -1)
  2312.             goto next;
  2313.  
  2314.         vert1 = LineDefs[linedef].start;
  2315.         vert2 = LineDefs[linedef].end;
  2316.  
  2317.         if(strcmp(SideDefs[sidedef].tex3, "-")) {
  2318.             strncpy(TextureName, SideDefs[sidedef].tex3, 8);
  2319.             goto got_one;
  2320.         }
  2321.  
  2322.         if(strcmp(SideDefs[sidedef].tex1, "-")) {
  2323.             strncpy(TextureName, SideDefs[sidedef].tex1, 8);
  2324.             goto got_one;
  2325.         }
  2326.  
  2327.         if(strcmp(SideDefs[sidedef].tex2, "-")) {
  2328.             strncpy(TextureName, SideDefs[sidedef].tex2, 8);
  2329.             goto got_one;
  2330.         }
  2331.  
  2332.         CurrentOffset = 0;
  2333.         PreviousWidth = 0;
  2334.         PreviousOffset = 0;
  2335.         goto next;
  2336.  
  2337. got_one:
  2338.  
  2339.         if (FirstTime) {
  2340.             FirstTime = FALSE;
  2341.             InitOffset = 0;
  2342.  
  2343.             /* ask for initial offset if UseOffset is true */
  2344.  
  2345.             if(!(t_info = FindTexture(TextureName)))
  2346.                 goto next;
  2347.             TextureWidth = t_info->width;
  2348.             
  2349.             if(UseOffset == TRUE) {
  2350.                 BCINT  x0, y0, key;   
  2351.                 char prompt[80]; 
  2352.  
  2353.                 if(UseMouse)
  2354.                     HideMousePointer();
  2355.  
  2356.                 sprintf(prompt, "Enter initial offset between 0 and %d", TextureWidth - 1);
  2357.  
  2358.                 x0 = (ScrMaxX - 25 - 8 * strlen(prompt)) / 2;
  2359.                 y0 = (ScrMaxY - 55) / 2;
  2360.  
  2361.                 DrawScreenBox3D( x0, y0, x0 + 25 + 8 * strlen( prompt), y0 + 55);
  2362.                 SetColor(WHITE);
  2363.                 DrawScreenText( x0 + 10, y0 + 8, prompt);
  2364.  
  2365.                 while (((key=InputInteger(x0+10, y0+28, &InitOffset, 0, TextureWidth))&0x00FF)!=0x000D
  2366.                             && (key & 0x00FF) != 0x001B)
  2367.                     Beep();
  2368.  
  2369.                 if (UseMouse)
  2370.                     ShowMousePointer();
  2371.             }
  2372.  
  2373.              CurrentOffset = InitOffset; 
  2374.             PreviousOffset = CurrentOffset;
  2375.             PreviousWidth = ComputeDist( Vertexes[ vert2].x - Vertexes[ vert1].x, Vertexes[ vert2].y - Vertexes[ vert1].y);
  2376.             strncpy(PreviousTexture, TextureName, 8);
  2377.             if(side == 1) {
  2378.                 SideDefs[sidedef].xoff = CurrentOffset;
  2379.             }
  2380.             else {
  2381.                 SideDefs[sidedef].xoff = TextureWidth - CurrentOffset;
  2382.             }
  2383.              goto next; 
  2384.         }
  2385.  
  2386.         if(!(t_info = FindTexture(TextureName)))
  2387.             goto next;
  2388.         TextureWidth = t_info->width;
  2389.  
  2390.         if((strcmp(PreviousTexture, TextureName)) && !NoChecking) {
  2391.             CurrentOffset = 0;
  2392.             PreviousOffset = 0;
  2393.         }
  2394.         else {
  2395.             CurrentOffset = (PreviousOffset + PreviousWidth) % TextureWidth;
  2396.             PreviousOffset = CurrentOffset;
  2397.         }
  2398.  
  2399.         SideDefs[sidedef].xoff = CurrentOffset;
  2400.  
  2401.         strncpy(PreviousTexture, TextureName, 8);
  2402.         PreviousWidth = ComputeDist( Vertexes[ vert2].x - Vertexes[ vert1].x, Vertexes[ vert2].y - Vertexes[ vert1].y);
  2403.  
  2404. next:
  2405.         ldlist = (ldlist)->next;
  2406.     }
  2407.     
  2408.     delete_list(listhead);
  2409.  
  2410.     MadeChanges = TRUE;
  2411. }
  2412.  
  2413. SelPtr rev_list(SelPtr list)
  2414. {
  2415.     SelPtr newlist = NULL, t;
  2416.  
  2417.     while(list) {
  2418.         t = GetMemory(sizeof(struct SelectionList));
  2419.         t->objnum = list->objnum;
  2420.         t->next = newlist;
  2421.         newlist = t;
  2422.         list = list->next;
  2423.     }
  2424.     return newlist;
  2425. }
  2426.  
  2427. void delete_list(SelPtr list)
  2428. {
  2429.     SelPtr t;
  2430.  
  2431.     while(list) {
  2432.         t = list->next;
  2433.         FreeMemory(list);
  2434.         list = t;
  2435.     }
  2436. }
  2437.  
  2438. BCINT CommonVertex(BCINT ld1, BCINT ld2)
  2439. {
  2440.     BCINT ld1s = LineDefs[ld1].start;
  2441.     BCINT ld1e = LineDefs[ld1].end;
  2442.     BCINT ld2s = LineDefs[ld2].start;
  2443.     BCINT ld2e = LineDefs[ld2].end;
  2444.     char errormessage[80];
  2445.  
  2446.     if((ld1s == ld2s) || (ld1s == ld2e))
  2447.         return ld1s;
  2448.  
  2449.     if((ld1e == ld2s) || (ld1e == ld2e))
  2450.         return ld1e;
  2451.  
  2452.     Beep();
  2453.     sprintf( errormessage, "LineDefs #%d and #%d are not joined", ld1, ld2);
  2454.     Notify( -1, -1, errormessage, NULL);
  2455.     return -1;
  2456. }
  2457.  
  2458.  
  2459. /*
  2460.    Distribute sector light levels
  2461.    */
  2462.  
  2463. void DistributeLightLevels( SelPtr obj) /* SWAP! */
  2464. {
  2465.     SelPtr cur;
  2466.     BCINT  n, num, light1, light2;
  2467.     
  2468.     ObjectsNeeded( OBJ_SECTORS, 0);
  2469.     
  2470.     num = 0;
  2471.     for (cur = obj; cur->next; cur = cur->next)
  2472.     num++;
  2473.     
  2474.     light1 = Sectors[ obj->objnum].light;
  2475.     light2 = Sectors[ cur->objnum].light;
  2476.     
  2477.     n = 0;
  2478.     for (cur = obj; cur; cur = cur->next) {
  2479.     Sectors[ cur->objnum].light = light1 + n * (light2 - light1) / num;
  2480.     n++;
  2481.     }
  2482.     MadeChanges = TRUE;
  2483. }
  2484.  
  2485.  
  2486.  
  2487. /*
  2488.    Distribute sector floor heights
  2489.    */
  2490.  
  2491. void DistributeSectorFloors( SelPtr obj) /* SWAP! */
  2492. {
  2493.     SelPtr cur;
  2494.     BCINT  n, num, floor1h, floor2h;
  2495.     
  2496.     ObjectsNeeded( OBJ_SECTORS, 0);
  2497.     
  2498.     num = 0;
  2499.     for (cur = obj; cur->next; cur = cur->next)
  2500.     num++;
  2501.     
  2502.     floor1h = Sectors[ obj->objnum].floorh;
  2503.     floor2h = Sectors[ cur->objnum].floorh;
  2504.     
  2505.     n = 0;
  2506.     for (cur = obj; cur; cur = cur->next) {
  2507.     Sectors[ cur->objnum].floorh = floor1h + n * (floor2h - floor1h) / num;
  2508.     n++;
  2509.     }
  2510.     MadeChanges = TRUE;
  2511. }
  2512.  
  2513.  
  2514.  
  2515. /*
  2516.    Distribute sector ceiling heights
  2517.    */
  2518.  
  2519. void DistributeSectorCeilings( SelPtr obj) /* SWAP! */
  2520. {
  2521.     SelPtr cur;
  2522.     BCINT n, num, ceil1h, ceil2h;
  2523.     
  2524.     ObjectsNeeded( OBJ_SECTORS, 0);
  2525.     
  2526.     num = 0;
  2527.     for (cur = obj; cur->next; cur = cur->next)
  2528.     num++;
  2529.     
  2530.     ceil1h = Sectors[ obj->objnum].ceilh;
  2531.     ceil2h = Sectors[ cur->objnum].ceilh;
  2532.     
  2533.     n = 0;
  2534.     for (cur = obj; cur; cur = cur->next) {
  2535.     Sectors[ cur->objnum].ceilh = ceil1h + n * (ceil2h - ceil1h) / num;
  2536.     n++;
  2537.     }
  2538.     MadeChanges = TRUE;
  2539. }
  2540.  
  2541.  
  2542.  
  2543. /* end of file */
  2544.