home *** CD-ROM | disk | FTP | other *** search
/ The Complete Doom Accessory Pack 2 / TheCompleteDoomAccessoryPackVolumeII.iso / editors / gdredit / gdredit.cpp < prev    next >
Text File  |  1994-07-25  |  78KB  |  2,549 lines

  1. #include "doom.h"
  2. #include "gdredit.h"
  3. #include <mem.h>
  4. #include <stdio.h>
  5. #include <commdlg.h>
  6. #include <io.h>
  7. #include <fcntl.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <fstream.h>
  11.  
  12.  
  13. #define BUFFER_SIZE    132
  14. #define MAX_THINGS            120
  15. #define MAX_UNKNOWNS        40
  16. #define MainClassName         "GDREdit"
  17. #define MAX_OBJECTS            50
  18. #define VERTEX_SIZE            3
  19. #define RED_COLOUR            RGB (255,0,0)
  20. #define YELLOW_COLOUR        RGB (255,255,95)
  21. #define BLUE_COLOUR            RGB (0,0,160)
  22.  
  23. #define SECTION_NAME        "CONFIG"
  24. #define PROFILE_FILE        "GDREDIT.INI"
  25.  
  26. // Edit modes.
  27. #define THING_EDIT            1
  28. #define VERTEX_EDIT            2
  29. #define LINEDEF_EDIT        3
  30. #define SECTOR_EDIT            4
  31.  
  32. #define REDRAW_MESSAGE        WM_USER + 1
  33. #define ADD_MESSAGE            WM_USER + 2
  34. #define DELETE_MESSAGE        WM_USER + 3
  35.  
  36.  
  37. // Our fabulous global variable area.
  38. HWND                     hInst;
  39. HWND                     hWndMain;
  40. HWND                    hWndButtonBar;
  41. HWND                    hWndThing;
  42. HWND                    hWndSector;
  43. HWND                    hWndLineDef;
  44. HWND                    hWndSideDef;
  45. Header                    DoomHeader;
  46. DirectoryEntry *        DoomDirectory = NULL;
  47. DoomObject *            DoomObjects [MAX_OBJECTS];
  48. int                        StartObject;
  49. int                        EndObject;
  50. int                        NoOfDoomObjects;
  51. int                        CurrentThing = -1;
  52. int                        CurrentVertex = -1;
  53. int                        CurrentSector = -1;
  54. int                        CurrentLineDef = -1;
  55. int                        CurrentLeftDef = -1;
  56. int                        CurrentRightDef = -1;
  57. int                        LastLineDef = -1;
  58. int                        UseSide1;
  59. int                        SectorOn = FALSE;
  60. int                        Scale;
  61. int                        OffsetX;
  62. int                        OffsetY;
  63. int                        ThingSize;
  64. int                        MouseDown = FALSE;
  65. int                        MoveMode = FALSE;
  66. char                    FileName [20];
  67. int                        EditMode = THING_EDIT;
  68. int                        ObjectList [512];
  69. int                        NoOfListObjects;
  70. int                        GridSnap;
  71. int                        GridSize;
  72. HPEN                    YellowPen;
  73. HPEN                    RedPen;
  74. HPEN                    BluePen;
  75. HBRUSH                    RedBrush;
  76. HBRUSH                    BlueBrush;
  77. int                        LineDefAddMode;
  78. int                        SectorAddMode;
  79. int                        FromVertex;
  80. int                        ToVertex;
  81. char                    DoomWadName [80];
  82. char                    DoomWadPath [80];
  83. int                        Registered = FALSE;
  84.  
  85.  
  86. BOOL FAR PASCAL ChooseLevelProc (HWND hWndDlg, WORD Message, WORD wParam, LONG lParam)
  87. {
  88.     switch (Message)
  89.     {
  90.         case WM_INITDIALOG:
  91.         {
  92.             char    Text [10];
  93.             int        Loop;
  94.             
  95.             // Load the level names into the list box.
  96.             for (Loop = 0;Loop < DoomHeader.NumberOfEntries;Loop++)
  97.             {
  98.                 if (DoomDirectory [Loop].ResourceName [0] == 'E')
  99.                 {
  100.                     strncpy (Text,DoomDirectory [Loop].ResourceName,8);
  101.                     SendDlgItemMessage (hWndDlg,10,LB_ADDSTRING,0,(LONG) Text);
  102.                 }
  103.             }
  104.             
  105.             SendDlgItemMessage (hWndDlg,10,LB_SETCURSEL,0,0);
  106.         }
  107.            break;
  108.  
  109.         case WM_CLOSE:
  110.              PostMessage (hWndDlg,WM_COMMAND,IDCANCEL,0L);
  111.              break;
  112.  
  113.         case WM_COMMAND:
  114.             switch (wParam)
  115.                {
  116.                 case 10: // The list box.
  117.                     if (HIWORD (lParam) == LBN_DBLCLK)
  118.                         SendMessage (hWndDlg,WM_COMMAND,IDOK,0L);
  119.                     break;
  120.                     
  121.                 case IDOK:
  122.                 {
  123.                     char    Text [10];
  124.                     int        Loop;
  125.                     int        Loop2;
  126.                     int        Done;
  127.                     
  128.                     // Set up the globals to whichever level was selected.
  129.                     SendDlgItemMessage (hWndDlg,10,LB_GETTEXT,(WORD) SendDlgItemMessage (hWndDlg,10,LB_GETCURSEL,0,0L),(LONG) Text);
  130.                     for (Loop = 0;Loop < DoomHeader.NumberOfEntries;Loop++)
  131.                     {
  132.                         if (strncmp (DoomDirectory [Loop].ResourceName,Text,8) == 0)
  133.                         {
  134.                             StartObject = Loop;
  135.                             EndObject = (int) DoomHeader.NumberOfEntries;
  136.                             Loop2 = Loop + 1;
  137.                             Done = FALSE;
  138.                             do
  139.                             {
  140.                                 if (DoomDirectory [Loop2].ResourceName [0] == 'E')
  141.                                 {
  142.                                     EndObject = Loop2;
  143.                                     Done = TRUE;
  144.                                 }
  145.                                 Loop2++;
  146.                             } while ((Loop2 < DoomHeader.NumberOfEntries) && (!Done));
  147.                         }
  148.                     }
  149.                     
  150.                      EndDialog (hWndDlg,TRUE);
  151.                  }
  152.                  break;
  153.                      
  154.                 case IDCANCEL:
  155.                      EndDialog (hWndDlg,FALSE);
  156.                      break;
  157.                }
  158.              break;
  159.  
  160.         default:
  161.             return FALSE;
  162.     }
  163.     return TRUE;
  164. }
  165.  
  166.  
  167. void UnloadWadFile ()
  168. {
  169.     int        Loop;
  170.     
  171.     // Delete all our objects in the system.
  172.     for (Loop = 0;Loop < NoOfDoomObjects;Loop++)
  173.         delete DoomObjects [Loop];
  174.  
  175.     // Get rid of the directory.
  176.     if (DoomDirectory)
  177.     {
  178.         delete [] DoomDirectory;
  179.         DoomDirectory = NULL;
  180.     }
  181.     
  182.     // Reset the globals.
  183.     StartObject = 0;
  184.     EndObject = 0;
  185.     NoOfDoomObjects = 0;
  186.     CurrentThing = -1;
  187.     CurrentLineDef = -1;
  188.     LastLineDef = -1;
  189.     CurrentSector = -1;
  190.     CurrentVertex = -1;
  191.     CurrentLeftDef = -1;
  192.     CurrentRightDef = -1;
  193.     NoOfListObjects = 0;
  194.     FileName [0] = '\000';
  195.  
  196.     // Reset the drawing area or there will be divide by zero errors
  197.     // when editing new wads.
  198.     Scale = 8;
  199.     OffsetX = 0;
  200.     OffsetY = 0;
  201. }
  202.  
  203.  
  204. void ReadWadFile (char * WadFileName)
  205. {
  206.     int            FileHandle;
  207.     int            Done;
  208.     int            Loop;
  209.     FARPROC        MsgProc;
  210.     int            Result;
  211.     int            NoOfLevels = 0;
  212.     
  213.     // Unload current wad file if one exists.
  214.     UnloadWadFile ();
  215.  
  216.     // Read in the header and directory with room to add entries.
  217.     FileHandle = open (WadFileName,O_BINARY|O_RDONLY);
  218.     read (FileHandle,&DoomHeader,sizeof (Header));
  219.     DoomDirectory = new DirectoryEntry [DoomHeader.NumberOfEntries + 100];
  220.     lseek (FileHandle,DoomHeader.DirectoryPointer,SEEK_SET);
  221.     lread (FileHandle,DoomDirectory,sizeof (DirectoryEntry) * DoomHeader.NumberOfEntries);
  222.  
  223.     // Load the level names into the list box.
  224.     for (Loop = 0;Loop < DoomHeader.NumberOfEntries;Loop++)
  225.     {
  226.         if (DoomDirectory [Loop].ResourceName [0] == 'E')
  227.             NoOfLevels++;
  228.     }
  229.  
  230.     // Display a list of levels and select one.
  231.     if (NoOfLevels > 1)
  232.     {
  233.         MsgProc = MakeProcInstance ((FARPROC) ChooseLevelProc,hInst);
  234.         Result = DialogBox (hInst,(LPSTR) "CHOOSE_BOX",hWndMain,MsgProc);
  235.         FreeProcInstance (MsgProc);
  236.         if (!Result)
  237.             return;
  238.     }
  239.     else
  240.     {
  241.         // Only one level. Load all the stuff in.
  242.         EndObject = (int) DoomHeader.NumberOfEntries;
  243.     }
  244.     
  245.     // Load up our selected level.
  246.     for (Loop = StartObject;Loop < EndObject;Loop++)
  247.     {
  248.         Done = FALSE;
  249.         
  250.         if (strncmp (DoomDirectory [Loop].ResourceName,"VERTEXES",8) == 0)
  251.         {
  252.             int        MinX = 32000;
  253.             int        MinY = 32000;
  254.             int        MaxX = -32000;
  255.             int        MaxY = -32000;
  256.             int        InnerLoop;
  257.             
  258.             Done = TRUE;
  259.             DoomObjects [NoOfDoomObjects] = new DoomVertexObject (FileHandle,&DoomDirectory [Loop]);
  260.             VertexPointer = (DoomVertexObject *) DoomObjects [NoOfDoomObjects];
  261.             if (VertexPointer->NoOfObjects > 0)
  262.                 CurrentVertex = 0;
  263.  
  264.             // Now find a good viewing point to survey our kingdom from.
  265.             Scale = 8;
  266.             for (InnerLoop = 0;InnerLoop < VertexPointer->NoOfObjects;InnerLoop++)
  267.             {
  268.                 MinX = min (VertexPointer->Data [InnerLoop].X,MinX);
  269.                 MinY = min (VertexPointer->Data [InnerLoop].Y,MinY);
  270.                 MaxX = max (VertexPointer->Data [InnerLoop].X,MaxX);
  271.                 MaxY = max (VertexPointer->Data [InnerLoop].Y,MaxY);
  272.             }
  273.             OffsetX = -(MinX + MaxX) / 2 + (400 * Scale);
  274.             OffsetY = -(MinY + MaxY) / 2 - (300 * Scale);
  275.         }
  276.             
  277.         if (strncmp (DoomDirectory [Loop].ResourceName,"LINEDEFS",8) == 0)
  278.         {
  279.             Done = TRUE;
  280.             DoomObjects [NoOfDoomObjects] = new DoomLineDefObject (FileHandle,&DoomDirectory [Loop]);
  281.             if (LineDefPointer->NoOfObjects > 0)
  282.                 CurrentLineDef = 0;
  283.         }
  284.         
  285.         if (strncmp (DoomDirectory [Loop].ResourceName,"THINGS",8) == 0)
  286.         {
  287.             Done = TRUE;
  288.             DoomObjects [NoOfDoomObjects] = new DoomThingObject (FileHandle,&DoomDirectory [Loop]);
  289.             if (ThingPointer->NoOfObjects > 0)
  290.                 CurrentThing = 0;
  291.         }
  292.         
  293.         if (strncmp (DoomDirectory [Loop].ResourceName,"SIDEDEFS",8) == 0)
  294.         {
  295.             Done = TRUE;
  296.             DoomObjects [NoOfDoomObjects] = new DoomSideDefObject (FileHandle,&DoomDirectory [Loop]);
  297.         }
  298.         
  299.         if (strncmp (DoomDirectory [Loop].ResourceName,"SECTORS",8) == 0)
  300.         {
  301.             Done = TRUE;
  302.             DoomObjects [NoOfDoomObjects] = new DoomSectorObject (FileHandle,&DoomDirectory [Loop]);
  303.             if (SectorPointer->NoOfObjects > 0)
  304.                 CurrentSector = 0;
  305.         }
  306.         
  307.         if (!Done)
  308.             DoomObjects [NoOfDoomObjects] = new DoomObject (FileHandle,&DoomDirectory [Loop]);
  309.         NoOfDoomObjects++;
  310.     }
  311.  
  312.     // Fill the dialogs with some default info.
  313.     SendMessage (hWndThing,REDRAW_MESSAGE,0,0L);
  314.     SendMessage (hWndSector,REDRAW_MESSAGE,0,0L);
  315.     SendMessage (hWndLineDef,REDRAW_MESSAGE,0,0L);
  316.     
  317.     // Clean up.
  318.     close (FileHandle);
  319. }
  320.  
  321.  
  322. void WriteWadFile (char * WadFileName)
  323. {
  324.     int        FileHandle;
  325.     int        Loop;
  326.     
  327.     // Write the header to hold a place for the real header.
  328.     FileHandle = open (WadFileName,O_BINARY|O_WRONLY|O_TRUNC|O_CREAT);
  329.     strncpy (DoomHeader.Signature,"PWAD",4);
  330.     DoomHeader.NumberOfEntries = NoOfDoomObjects;
  331.     write (FileHandle,&DoomHeader,sizeof (Header));
  332.  
  333.     // Save all the objects.
  334.     for (Loop = 0;Loop < NoOfDoomObjects;Loop++)
  335.         DoomObjects [Loop]->SaveObject (FileHandle,&DoomDirectory [StartObject + Loop]);
  336.  
  337.     // Pump out the directory, then a REAL copy of the header.
  338.     DoomHeader.DirectoryPointer = tell (FileHandle);
  339.     lwrite (FileHandle,&DoomDirectory [StartObject],(long) sizeof (DirectoryEntry) * (long) NoOfDoomObjects);
  340.     lseek (FileHandle,0L,SEEK_SET);
  341.     write (FileHandle,&DoomHeader,sizeof (Header));
  342.     
  343.     // Clean up.
  344.     close (FileHandle);
  345. }
  346.  
  347.  
  348. void NewWadFile ()
  349. {
  350.     // Unload current wad file if one exists.
  351.     UnloadWadFile ();
  352.     SetWindowText (hWndMain,"GDR Edit - NEW.WAD");
  353.     strcpy (FileName,"NEW.WAD");
  354.  
  355.     // Set up the header.
  356.     strncpy (DoomHeader.Signature,"PWAD",4);
  357.     DoomHeader.NumberOfEntries = 11;
  358.     NoOfDoomObjects = 11;
  359.     
  360.     // Set up the directory with spare room in it.
  361.     DoomDirectory = new DirectoryEntry [DoomHeader.NumberOfEntries + 100];
  362.     memset (DoomDirectory,0,(int (DoomHeader.NumberOfEntries) + 100) * sizeof (DirectoryEntry));
  363.  
  364.     //  Load up the values for a base level.
  365.     strncpy (DoomDirectory [0].ResourceName,"E1M1",8);
  366.     DoomObjects [0] = new DoomObject ();
  367.     strncpy (DoomDirectory [1].ResourceName,"THINGS",8);
  368.     DoomObjects [1] = new DoomThingObject ();
  369.     strncpy (DoomDirectory [2].ResourceName,"LINEDEFS",8);
  370.     DoomObjects [2] = new DoomLineDefObject ();
  371.     strncpy (DoomDirectory [3].ResourceName,"SIDEDEFS",8);
  372.     DoomObjects [3] = new DoomSideDefObject ();
  373.     strncpy (DoomDirectory [4].ResourceName,"VERTEXES",8);
  374.     DoomObjects [4] = new DoomVertexObject ();
  375.     strncpy (DoomDirectory [5].ResourceName,"SEGS",8);
  376.     DoomObjects [5] = new DoomObject ();
  377.     strncpy (DoomDirectory [6].ResourceName,"SSECTORS",8);
  378.     DoomObjects [6] = new DoomObject ();
  379.     strncpy (DoomDirectory [7].ResourceName,"NODES",8);
  380.     DoomObjects [7] = new DoomObject ();
  381.     strncpy (DoomDirectory [8].ResourceName,"SECTORS",8);
  382.     DoomObjects [8] = new DoomSectorObject ();
  383.     strncpy (DoomDirectory [9].ResourceName,"REJECT",8);
  384.     DoomObjects [9] = new DoomObject ();
  385.     strncpy (DoomDirectory [10].ResourceName,"BLOCKMAP",8);
  386.     DoomObjects [10] = new DoomObject ();
  387.             
  388.     // Fill the dialogs with some default info.
  389.     InvalidateRect (hWndMain,NULL,TRUE);
  390.     SendMessage (hWndThing,REDRAW_MESSAGE,0,0L);
  391.     SendMessage (hWndSector,REDRAW_MESSAGE,0,0L);
  392.     SendMessage (hWndLineDef,REDRAW_MESSAGE,0,0L);
  393. }
  394.  
  395.  
  396. void LoadWadFile ()
  397. {
  398.     OPENFILENAME    FileOpenDialog;
  399.     char            Filter [] = "Data files (*.wad)\0*.wad\0All files (*.*)\0*.*\0";
  400.     char            Text [80];
  401.     char            FileName [20];
  402.  
  403.     // Setup for the common file open dialog.
  404.     memset (&FileOpenDialog,0,sizeof (FileOpenDialog));
  405.     FileOpenDialog.lStructSize = sizeof (FileOpenDialog);
  406.     FileOpenDialog.hWndOwner = hWndMain;
  407.     FileOpenDialog.hInstance = hInst;
  408.     FileOpenDialog.lpstrFilter = Filter;
  409.     FileOpenDialog.nFilterIndex = 1;
  410.     FileOpenDialog.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
  411.     FileOpenDialog.lpstrFileTitle = FileName;
  412.     
  413.     if (GetOpenFileName (&FileOpenDialog))
  414.     {
  415.         // Found a filename, process the file.
  416.         ReadWadFile (FileName);
  417.         sprintf (Text,"GDR Edit - %s",FileName);
  418.         SetWindowText (hWndMain,Text);
  419.         InvalidateRect (hWndMain,NULL,TRUE);
  420.     }
  421. }
  422.  
  423.  
  424. void SaveWadFile ()
  425. {
  426.     OPENFILENAME    FileSaveDialog;
  427.     char            Text [80];
  428.  
  429.     // Setup for the common file open dialog.
  430.     memset (&FileSaveDialog,0,sizeof (FileSaveDialog));
  431.     FileSaveDialog.lStructSize = sizeof (FileSaveDialog);
  432.     FileSaveDialog.hWndOwner = hWndMain;
  433.     FileSaveDialog.hInstance = hInst;
  434.     FileSaveDialog.lpstrFilter = "Data files (*.wad)\0*.wad\0All files (*.*)\0*.*\0";
  435.     FileSaveDialog.lpstrDefExt = "WAD";
  436.     FileSaveDialog.nFilterIndex = 1;
  437.     FileSaveDialog.Flags = OFN_PATHMUSTEXIST;
  438.     FileSaveDialog.lpstrFileTitle = FileName;
  439.     
  440.     // If we get a name, save the file.
  441.     if (GetSaveFileName (&FileSaveDialog))
  442.     {
  443.         WriteWadFile (FileName);
  444.         sprintf (Text,"GDR Edit - %s",FileName);
  445.         SetWindowText (hWndMain,Text);
  446.     }
  447. }
  448.  
  449.  
  450. void DrawLineDef (HDC DC,int EntryNo)
  451. {
  452.     int        MidX;
  453.     int        MidY;
  454.     int        EndX;
  455.     int        EndY;
  456.     int        Trim;
  457.     
  458.     // Draw the line itself.
  459.     MoveTo (DC,(VertexPointer->Data [LineDefPointer->Data [EntryNo].FromVertex].X + OffsetX) / Scale,-(VertexPointer->Data [LineDefPointer->Data [EntryNo].FromVertex].Y + OffsetY) / Scale);
  460.     LineTo (DC,(VertexPointer->Data [LineDefPointer->Data [EntryNo].ToVertex].X + OffsetX) / Scale,-(VertexPointer->Data [LineDefPointer->Data [EntryNo].ToVertex].Y + OffsetY) / Scale);
  461.     
  462.     // Place the tick mark.
  463.     if (EditMode == SECTOR_EDIT || EditMode == LINEDEF_EDIT)
  464.     {
  465.         // Get the midpoints.
  466.         MidX = (VertexPointer->Data [LineDefPointer->Data [EntryNo].FromVertex].X + VertexPointer->Data [LineDefPointer->Data [EntryNo].ToVertex].X) / 2;
  467.         MidY = (VertexPointer->Data [LineDefPointer->Data [EntryNo].FromVertex].Y + VertexPointer->Data [LineDefPointer->Data [EntryNo].ToVertex].Y) / 2;
  468.     
  469.         // Get the deltas.
  470.         EndX = VertexPointer->Data [LineDefPointer->Data [EntryNo].ToVertex].Y - VertexPointer->Data [LineDefPointer->Data [EntryNo].FromVertex].Y;
  471.         EndY = VertexPointer->Data [LineDefPointer->Data [EntryNo].FromVertex].X - VertexPointer->Data [LineDefPointer->Data [EntryNo].ToVertex].X;
  472.  
  473.         // Trim the deltas to a maximum value.
  474.         if (abs (EndX) >= abs (EndY))
  475.             Trim = abs (EndX) / 16;
  476.         else
  477.             Trim = abs (EndY) / 16;
  478.         if (Trim == 0)
  479.             Trim = 1;
  480.         EndX /= Trim;
  481.         EndY /= Trim;
  482.     
  483.         // Add our delta values.
  484.         EndX += MidX;
  485.         EndY += MidY;
  486.  
  487.         MoveTo (DC,(MidX + OffsetX) / Scale,-(MidY + OffsetY) / Scale);
  488.         LineTo (DC,(EndX + OffsetX) / Scale,-(EndY + OffsetY) / Scale);
  489.     }
  490. }
  491.  
  492.  
  493. void PaintIt (HDC DC)
  494. {
  495.     int        Loop;
  496.     RECT    Rect;
  497.  
  498.     // Setup for the draw.
  499.     SetROP2 (DC,R2_NOTMERGEPEN);
  500.  
  501.     // Draw some linedefs.
  502.     if (LineDefPointer && VertexPointer)
  503.     {
  504.         for (Loop = 0;Loop < LineDefPointer->NoOfObjects;Loop++)
  505.             DrawLineDef (DC,Loop);
  506.     }
  507.  
  508.     // Draw some vertexes.
  509.     if (VertexPointer && (EditMode == VERTEX_EDIT || EditMode == LINEDEF_EDIT || EditMode == SECTOR_EDIT))
  510.     {
  511.         for (Loop = 0;Loop < VertexPointer->NoOfObjects;Loop++)
  512.         {
  513.             SetRect (&Rect,(VertexPointer->Data [Loop].X + OffsetX) / Scale - VERTEX_SIZE,-(VertexPointer->Data [Loop].Y + OffsetY) / Scale - VERTEX_SIZE,(VertexPointer->Data [Loop].X + OffsetX) / Scale + VERTEX_SIZE,-(VertexPointer->Data [Loop].Y + OffsetY) / Scale + VERTEX_SIZE);
  514.             InvertRect (DC,&Rect);
  515.         }
  516.     }
  517.     
  518.     // Draw some things.
  519.     if (ThingPointer && (EditMode == THING_EDIT))
  520.     {
  521.         // Set the size a thing should be drawn at.
  522.         ThingSize = 16 / Scale;
  523.         if (ThingSize < 2)
  524.             ThingSize = 2;
  525.             
  526.         // Draw all the things.
  527.         for (Loop = 0;Loop < ThingPointer->NoOfObjects;Loop++)
  528.         {
  529.             SetRect (&Rect,(ThingPointer->Data [Loop].X + OffsetX) / Scale - ThingSize,-(ThingPointer->Data [Loop].Y + OffsetY) / Scale - ThingSize,(ThingPointer->Data [Loop].X + OffsetX) / Scale + ThingSize,-(ThingPointer->Data [Loop].Y + OffsetY) / Scale + ThingSize);
  530.             InvertRect (DC,&Rect);
  531.         }
  532.     }
  533.  
  534.     // Draw the highlighted linedef.
  535.     SetROP2 (DC,R2_COPYPEN);
  536.     SelectObject (DC,RedPen);
  537.     if (LineDefPointer && EditMode == LINEDEF_EDIT && CurrentLineDef >= 0)
  538.         DrawLineDef (DC,CurrentLineDef);
  539.  
  540.     // If we have a sector then we should highlight it.
  541.     if (SectorPointer && EditMode == SECTOR_EDIT && CurrentSector >= 0)
  542.         for (Loop = 0;Loop < NoOfListObjects;Loop++)
  543.             DrawLineDef (DC,ObjectList [Loop]);
  544. }
  545.  
  546.  
  547. BOOL FAR PASCAL ButtonBarMsgProc (HWND hWndDlg, WORD Message, WORD wParam, LONG lParam)
  548. {
  549.     switch (Message)
  550.     {
  551.         case WM_COMMAND:
  552.             switch (wParam)
  553.                {
  554.                 case 202:
  555.                     // Up arrow.
  556.                     OffsetY -= 20 * Scale;
  557.                     InvalidateRect (hWndMain,NULL,TRUE);
  558.                     break;
  559.  
  560.                 case 203:
  561.                     // Down arrow.
  562.                     OffsetY += 20 * Scale;
  563.                     InvalidateRect (hWndMain,NULL,TRUE);
  564.                     break;
  565.  
  566.                 case 204:
  567.                     // Left arrow.
  568.                     OffsetX += 20 * Scale;
  569.                     InvalidateRect (hWndMain,NULL,TRUE);
  570.                     break;
  571.  
  572.                 case 205:
  573.                     // Right arrow.
  574.                     OffsetX -= 20 * Scale;
  575.                     InvalidateRect (hWndMain,NULL,TRUE);
  576.                     break;
  577.                     
  578.                 case 206: // Zoom in.
  579.                     // Zoom in for detail work.
  580.                     if (Scale > 1)
  581.                     {
  582.                         Scale--;
  583.                         OffsetX -= 400;
  584.                         OffsetY += 300;
  585.                         InvalidateRect (hWndMain,NULL,TRUE);
  586.                     }
  587.                     break;
  588.                     
  589.                 case 207: // Zoom out
  590.                     // Zoom out for overall view.
  591.                     if (Scale < 20)
  592.                     {
  593.                         Scale++;
  594.                         OffsetX += 400;
  595.                         OffsetY -= 300;
  596.                         InvalidateRect (hWndMain,NULL,TRUE);
  597.                     }
  598.                     break;
  599.  
  600.                 case 212:
  601.                     // Add something.
  602.                     SendMessage (hWndMain,ADD_MESSAGE,0,0L);
  603.                     break;
  604.                     
  605.                 case 213:
  606.                     // Delete something.
  607.                     SendMessage (hWndMain,DELETE_MESSAGE,0,0L);
  608.                     break;
  609.                }
  610.              break;
  611.  
  612.         default:
  613.             return FALSE;
  614.     }
  615.     return TRUE;
  616. }
  617.  
  618. // ╔════════════════════════════════════════════════════════════════════════╗
  619. // ║                            Thing Editing                               ║
  620. // ║                                                                        ║
  621. // ║ Allow the adding, moving, changing and deleting of things in the .WAD  ║
  622. // ║ file.                                                                  ║
  623. // ╚════════════════════════════════════════════════════════════════════════╝
  624.  
  625. int FindThatThing (int X,int Y)
  626. {
  627.     int        Loop;
  628.     long    DX;
  629.     long    DY;
  630.     long    Min = 1000000L;
  631.     long    Value;
  632.     int        Selected = -1;
  633.     RECT    Rect;
  634.     POINT    Point;
  635.  
  636.     Point.x = X;
  637.     Point.y = Y;
  638.         
  639.     if (ThingPointer)
  640.     {
  641.         // Check for an exact hit first.
  642.         for (Loop = 0;Loop < ThingPointer->NoOfObjects;Loop++)
  643.         {
  644.             SetRect (&Rect,(ThingPointer->Data [Loop].X + OffsetX) / Scale - ThingSize,-(ThingPointer->Data [Loop].Y + OffsetY) / Scale - ThingSize,(ThingPointer->Data [Loop].X + OffsetX) / Scale + ThingSize,-(ThingPointer->Data [Loop].Y + OffsetY) / Scale + ThingSize);
  645.             if (PtInRect (&Rect,Point))
  646.                 return Loop;
  647.         }
  648.         
  649.         // Try for the nearest instead.
  650.         for (Loop = 0;Loop < ThingPointer->NoOfObjects;Loop++)
  651.         {
  652.             DX = (long) (ThingPointer->Data [Loop].X + OffsetX) / Scale - X;
  653.             DY = (long) -(ThingPointer->Data [Loop].Y + OffsetY) / Scale - Y;
  654.             Value = DX * DX + DY * DY;
  655.             if (Value < Min)
  656.             {
  657.                 Min = Value;
  658.                 Selected = Loop;
  659.             }
  660.         }
  661.     }
  662.     
  663.     return Selected;
  664. }
  665.  
  666.  
  667. BOOL FAR PASCAL ThingProc (HWND hWndDlg, WORD Message, WORD wParam, LONG lParam)
  668. {
  669.     switch (Message)
  670.         {
  671.         case WM_INITDIALOG:
  672.         {
  673.             fstream        InActivityFile;
  674.             char        Buffer [BUFFER_SIZE];
  675.             char        Text [BUFFER_SIZE];
  676.             int            ItemType;
  677.             char *        CopyFrom;
  678.                     
  679.             InActivityFile.open ("GDREDIT.INI",ios::in|ios::nocreate);
  680.             if (!InActivityFile.fail ())
  681.             {
  682.                 // Get to the start of the section we want.
  683.                 do
  684.                 {
  685.                     InActivityFile.getline (Buffer,BUFFER_SIZE);
  686.                 } while (!InActivityFile.eof () && strcmp (Buffer,"[THINGS]") != 0);
  687.                 InActivityFile.getline (Buffer,BUFFER_SIZE);
  688.                 
  689.                 while (!InActivityFile.eof () && Buffer [0] != '[')
  690.                 {
  691.                     if (strlen (Buffer) > 0)
  692.                     {
  693.                         ItemType = atoi (Buffer);
  694.                         CopyFrom = strstr (Buffer,",");
  695.                         if (CopyFrom != NULL)
  696.                             strcpy (Text,CopyFrom + 1);
  697.                         SendDlgItemMessage (hWndDlg,10,CB_SETITEMDATA,(WORD) SendDlgItemMessage (hWndDlg,10,CB_ADDSTRING,0,(LONG) Text),(LONG) ItemType);
  698.                     }
  699.                 
  700.                     InActivityFile.getline (Buffer,BUFFER_SIZE);
  701.                 }
  702.                 InActivityFile.close ();
  703.             }
  704.             SendDlgItemMessage (hWndDlg,10,CB_SETCURSEL,0,0);
  705.         }
  706.            break;
  707.             
  708.         case REDRAW_MESSAGE: // Update the window.
  709.         {
  710.             int        Loop;
  711.             int        ListCount;
  712.             int        Finished = FALSE;
  713.             int        Entry = -1;
  714.             
  715.             // Update our display.
  716.             if (ThingPointer && CurrentThing >= 0)
  717.             {
  718.                 Loop = -1;
  719.                 ListCount = (int) SendDlgItemMessage (hWndDlg,10,CB_GETCOUNT,0,0L);
  720.                 do
  721.                 {
  722.                     Loop++;
  723.                     if (SendDlgItemMessage (hWndDlg,10,CB_GETITEMDATA,Loop,0) == ThingPointer->Data [CurrentThing].Type)
  724.                     {
  725.                         Finished = TRUE;
  726.                         Entry = Loop;
  727.                     }
  728.                 } while ((!Finished) && (Loop < ListCount - 1));
  729.                 SendDlgItemMessage (hWndDlg,10,CB_SETCURSEL,Entry,0);
  730.                     
  731.                 CheckDlgButton (hWndDlg,11,ThingPointer->Data [CurrentThing].Bitset & 1);
  732.                 CheckDlgButton (hWndDlg,12,ThingPointer->Data [CurrentThing].Bitset & 2);
  733.                 CheckDlgButton (hWndDlg,13,ThingPointer->Data [CurrentThing].Bitset & 4);
  734.                 CheckDlgButton (hWndDlg,14,ThingPointer->Data [CurrentThing].Bitset & 8);
  735.                 CheckDlgButton (hWndDlg,15,ThingPointer->Data [CurrentThing].Bitset & 16);
  736.                 SetDlgItemInt (hWndDlg,16,ThingPointer->Data [CurrentThing].Angle,TRUE);
  737.             }
  738.         }
  739.         break;
  740.         
  741.         case WM_COMMAND:
  742.             if (ThingPointer && CurrentThing >= 0)
  743.             {
  744.                 switch (wParam)
  745.                    {
  746.                     case 10: // Type of object.
  747.                         if (HIWORD (lParam) == CBN_SELCHANGE)
  748.                             ThingPointer->Data [CurrentThing].Type = (int) SendDlgItemMessage (hWndDlg,10,CB_GETITEMDATA,(WORD) SendDlgItemMessage (hWndDlg,10,CB_GETCURSEL,0,0),0);
  749.                         break;
  750.                         
  751.                     case 11: // Level 1
  752.                         if (ThingPointer->Data [CurrentThing].Bitset & 1)
  753.                             ThingPointer->Data [CurrentThing].Bitset = ThingPointer->Data [CurrentThing].Bitset - 1;
  754.                         else
  755.                             ThingPointer->Data [CurrentThing].Bitset = ThingPointer->Data [CurrentThing].Bitset + 1;
  756.                         break;
  757.  
  758.                     case 12: // Levels 2 & 3
  759.                         if (ThingPointer->Data [CurrentThing].Bitset & 2)
  760.                             ThingPointer->Data [CurrentThing].Bitset = ThingPointer->Data [CurrentThing].Bitset - 2;
  761.                         else
  762.                             ThingPointer->Data [CurrentThing].Bitset = ThingPointer->Data [CurrentThing].Bitset + 2;
  763.                         break;
  764.  
  765.                     case 13: // Levels 4 & 5
  766.                         if (ThingPointer->Data [CurrentThing].Bitset & 4)
  767.                             ThingPointer->Data [CurrentThing].Bitset = ThingPointer->Data [CurrentThing].Bitset - 4;
  768.                         else
  769.                             ThingPointer->Data [CurrentThing].Bitset = ThingPointer->Data [CurrentThing].Bitset + 4;
  770.                         break;
  771.  
  772.                     case 14: // Deaf bugger.
  773.                         if (ThingPointer->Data [CurrentThing].Bitset & 8)
  774.                             ThingPointer->Data [CurrentThing].Bitset = ThingPointer->Data [CurrentThing].Bitset - 8;
  775.                         else
  776.                             ThingPointer->Data [CurrentThing].Bitset = ThingPointer->Data [CurrentThing].Bitset + 8;
  777.                         break;
  778.  
  779.                     case 15: // Net game.
  780.                         if (ThingPointer->Data [CurrentThing].Bitset & 16)
  781.                             ThingPointer->Data [CurrentThing].Bitset = ThingPointer->Data [CurrentThing].Bitset - 16;
  782.                         else
  783.                             ThingPointer->Data [CurrentThing].Bitset = ThingPointer->Data [CurrentThing].Bitset + 16;
  784.                         break;
  785.  
  786.                     case 204:
  787.                         ThingPointer->Data [CurrentThing].Angle = 0;
  788.                         SetDlgItemInt (hWndDlg,16,ThingPointer->Data [CurrentThing].Angle,TRUE);
  789.                         break;
  790.  
  791.                     case 208:
  792.                         ThingPointer->Data [CurrentThing].Angle = 45;
  793.                         SetDlgItemInt (hWndDlg,16,ThingPointer->Data [CurrentThing].Angle,TRUE);
  794.                         break;
  795.  
  796.                     case 202:
  797.                         ThingPointer->Data [CurrentThing].Angle = 90;
  798.                         SetDlgItemInt (hWndDlg,16,ThingPointer->Data [CurrentThing].Angle,TRUE);
  799.                         break;
  800.  
  801.                     case 209:
  802.                         ThingPointer->Data [CurrentThing].Angle = 135;
  803.                         SetDlgItemInt (hWndDlg,16,ThingPointer->Data [CurrentThing].Angle,TRUE);
  804.                         break;
  805.  
  806.                     case 205:
  807.                         ThingPointer->Data [CurrentThing].Angle = 180;
  808.                         SetDlgItemInt (hWndDlg,16,ThingPointer->Data [CurrentThing].Angle,TRUE);
  809.                         break;
  810.  
  811.                     case 210:
  812.                         ThingPointer->Data [CurrentThing].Angle = 225;
  813.                         SetDlgItemInt (hWndDlg,16,ThingPointer->Data [CurrentThing].Angle,TRUE);
  814.                         break;
  815.  
  816.                     case 203:
  817.                         ThingPointer->Data [CurrentThing].Angle = 270;
  818.                         SetDlgItemInt (hWndDlg,16,ThingPointer->Data [CurrentThing].Angle,TRUE);
  819.                         break;
  820.  
  821.                     case 211:
  822.                         ThingPointer->Data [CurrentThing].Angle = 315;
  823.                         SetDlgItemInt (hWndDlg,16,ThingPointer->Data [CurrentThing].Angle,TRUE);
  824.                         break;
  825.                    }
  826.                }
  827.              break;
  828.  
  829.         default:
  830.             return FALSE;
  831.     }
  832.     return TRUE;
  833. }
  834.  
  835.  
  836. LONG FAR PASCAL ThingEdit (HWND hWnd, WORD Message, WORD wParam, LONG lParam)
  837. {
  838.     switch (Message)
  839.     {
  840.         case WM_RBUTTONDOWN: // They want to add/delete things.
  841.         {
  842.             RECT    Rect;
  843.             POINT    Point;
  844.             int        Done = FALSE;
  845.             int        Loop;
  846.             HDC        DC;
  847.  
  848.             Point.x = LOWORD (lParam);
  849.             Point.y = HIWORD (lParam);
  850.         
  851.             if (ThingPointer)
  852.             {
  853.                 // Check for an exact hit.
  854.                 for (Loop = 0;Loop < ThingPointer->NoOfObjects;Loop++)
  855.                 {
  856.                     SetRect (&Rect,(ThingPointer->Data [Loop].X + OffsetX) / Scale - ThingSize,-(ThingPointer->Data [Loop].Y + OffsetY) / Scale - ThingSize,(ThingPointer->Data [Loop].X + OffsetX) / Scale + ThingSize,-(ThingPointer->Data [Loop].Y + OffsetY) / Scale + ThingSize);
  857.                     if (PtInRect (&Rect,Point))
  858.                     {
  859.                         Done = TRUE;
  860.                         CurrentThing = Loop;
  861.                         SendMessage (hWndMain,DELETE_MESSAGE,0,0L);
  862.                     }
  863.                 }
  864.                 
  865.                 // Add a new thing instead.
  866.                 if (Done == FALSE)
  867.                 {
  868.                     CurrentThing = ThingPointer->Add (CurrentThing,LOWORD (lParam) * Scale - OffsetX,-(HIWORD (lParam) * Scale + OffsetY));
  869.                     DC = GetDC (hWndMain);
  870.                     SetRect (&Rect,(ThingPointer->Data [CurrentThing].X + OffsetX) / Scale - ThingSize,-(ThingPointer->Data [CurrentThing].Y + OffsetY) / Scale - ThingSize,(ThingPointer->Data [CurrentThing].X + OffsetX) / Scale + ThingSize,-(ThingPointer->Data [CurrentThing].Y + OffsetY) / Scale + ThingSize);
  871.                     InvertRect (DC,&Rect);
  872.                     ReleaseDC (hWndMain,DC);
  873.                     SendMessage (hWndThing,REDRAW_MESSAGE,0,0L);
  874.                 }
  875.             }
  876.         }
  877.         break;
  878.             
  879.         case WM_LBUTTONDOWN: // They want to move/edit something.
  880.         {
  881.             int        Result;
  882.             
  883.             Result = FindThatThing (LOWORD (lParam),HIWORD (lParam));
  884.             if (Result != -1)
  885.             {
  886.                 CurrentThing = Result;
  887.                 SendMessage (hWndThing,REDRAW_MESSAGE,0,0L);
  888.                 MouseDown = TRUE;
  889.             }
  890.         }
  891.         break;
  892.  
  893.         case WM_LBUTTONUP: // Cleanup after move.
  894.             MoveMode = FALSE;
  895.             MouseDown = FALSE;
  896.             break;
  897.     
  898.         case WM_MOUSEMOVE: // Check for drags.
  899.             if (MouseDown)
  900.             {
  901.                  RECT    Rect;
  902.                 HDC        DC;
  903.             
  904.                 // Erase object.
  905.                 MoveMode = TRUE;
  906.                 DC = GetDC (hWndMain);
  907.                 SetRect (&Rect,(ThingPointer->Data [CurrentThing].X + OffsetX) / Scale - ThingSize,-(ThingPointer->Data [CurrentThing].Y + OffsetY) / Scale - ThingSize,(ThingPointer->Data [CurrentThing].X + OffsetX) / Scale + ThingSize,-(ThingPointer->Data [CurrentThing].Y + OffsetY) / Scale + ThingSize);
  908.                 InvertRect (DC,&Rect);
  909.                 
  910.                 // Update position.
  911.                 ThingPointer->Data [CurrentThing].X = LOWORD (lParam) * Scale - OffsetX;
  912.                 ThingPointer->Data [CurrentThing].Y = -(HIWORD (lParam) * Scale + OffsetY);
  913.                 
  914.                 // Redraw object at new location.
  915.                 SetRect (&Rect,(ThingPointer->Data [CurrentThing].X + OffsetX) / Scale - ThingSize,-(ThingPointer->Data [CurrentThing].Y + OffsetY) / Scale - ThingSize,(ThingPointer->Data [CurrentThing].X + OffsetX) / Scale + ThingSize,-(ThingPointer->Data [CurrentThing].Y + OffsetY) / Scale + ThingSize);
  916.                 InvertRect (DC,&Rect);
  917.                 ReleaseDC (hWndMain,DC);
  918.             }
  919.             break;
  920.         
  921.         case DELETE_MESSAGE:
  922.         {
  923.             RECT    Rect;
  924.             HDC        DC;
  925.             
  926.             // Erase object.
  927.             DC = GetDC (hWndMain);
  928.             SetRect (&Rect,(ThingPointer->Data [CurrentThing].X + OffsetX) / Scale - ThingSize,-(ThingPointer->Data [CurrentThing].Y + OffsetY) / Scale - ThingSize,(ThingPointer->Data [CurrentThing].X + OffsetX) / Scale + ThingSize,-(ThingPointer->Data [CurrentThing].Y + OffsetY) / Scale + ThingSize);
  929.             InvertRect (DC,&Rect);
  930.             ThingPointer->Delete (CurrentThing);
  931.             ReleaseDC (hWndMain,DC);
  932.             
  933.             // Switch to the previous thing.
  934.             ThingPointer->Delete (CurrentThing);
  935.             CurrentThing--;
  936.             if (CurrentThing < 0)
  937.                 CurrentThing = ThingPointer->NoOfObjects - 1;
  938.                 
  939.             // Update the dialog box.    
  940.             SendMessage (hWndThing,REDRAW_MESSAGE,0,0L);
  941.         }
  942.         break;
  943.                     
  944.         default:
  945.             return DefWindowProc (hWnd,Message,wParam,lParam);
  946.     }
  947.     
  948.     return 0L;
  949. }
  950.  
  951. // ╔════════════════════════════════════════════════════════════════════════╗
  952. // ║                           Vertex Editing                               ║
  953. // ║                                                                        ║
  954. // ║ Pretty obvious.                                                        ║
  955. // ╚════════════════════════════════════════════════════════════════════════╝
  956.  
  957. int FindThatVertex (int X,int Y)
  958. {
  959.     int        Loop;
  960.     RECT    Rect;
  961.     POINT    Point;
  962.     long    DX;
  963.     long    DY;
  964.     long    Min = 1000000L;
  965.     long    Value;
  966.     int        Selected = -1;
  967.  
  968.     Point.x = X;
  969.     Point.y = Y;
  970.         
  971.     if (VertexPointer)
  972.     {
  973.         // Check for an exact hit first.
  974.         for (Loop = 0;Loop < VertexPointer->NoOfObjects;Loop++)
  975.         {
  976.             SetRect (&Rect,(VertexPointer->Data [Loop].X + OffsetX) / Scale - VERTEX_SIZE,-(VertexPointer->Data [Loop].Y + OffsetY) / Scale - VERTEX_SIZE,(VertexPointer->Data [Loop].X + OffsetX) / Scale + VERTEX_SIZE,-(VertexPointer->Data [Loop].Y + OffsetY) / Scale + VERTEX_SIZE);
  977.             if (PtInRect (&Rect,Point))
  978.                 return Loop;
  979.         }
  980.         
  981.         // Try for the nearest instead.
  982.         for (Loop = 0;Loop < VertexPointer->NoOfObjects;Loop++)
  983.         {
  984.             DX = (long) (VertexPointer->Data [Loop].X + OffsetX) / Scale - X;
  985.             DY = (long) -(VertexPointer->Data [Loop].Y + OffsetY) / Scale - Y;
  986.             Value = DX * DX + DY * DY;
  987.             if (Value < Min)
  988.             {
  989.                 Min = Value;
  990.                 Selected = Loop;
  991.             }
  992.         }
  993.     }
  994.     
  995.     return Selected;
  996. }
  997.  
  998.  
  999. LONG FAR PASCAL VertexEdit (HWND hWnd, WORD Message, WORD wParam, LONG lParam)
  1000. {
  1001.     switch (Message)
  1002.     {
  1003.         case WM_RBUTTONDOWN: // They want to add/delete vertexes.
  1004.         {
  1005.             RECT    Rect;
  1006.             POINT    Point;
  1007.             int        Done = FALSE;
  1008.             int        Loop;
  1009.             int        Loop2;
  1010.             HDC        DC;
  1011.  
  1012.             Point.x = LOWORD (lParam);
  1013.             Point.y = HIWORD (lParam);
  1014.         
  1015.             if (VertexPointer)
  1016.             {
  1017.                 // Setup time.
  1018.                 DC = GetDC (hWndMain);
  1019.                 SetROP2 (DC,R2_NOTMERGEPEN);
  1020.                 
  1021.                 // Check for an exact hit.
  1022.                 for (Loop = 0;Loop < VertexPointer->NoOfObjects;Loop++)
  1023.                 {
  1024.                     SetRect (&Rect,(VertexPointer->Data [Loop].X + OffsetX) / Scale - VERTEX_SIZE,-(VertexPointer->Data [Loop].Y + OffsetY) / Scale - VERTEX_SIZE,(VertexPointer->Data [Loop].X + OffsetX) / Scale + VERTEX_SIZE,-(VertexPointer->Data [Loop].Y + OffsetY) / Scale + VERTEX_SIZE);
  1025.                     if (PtInRect (&Rect,Point))
  1026.                     {
  1027.                         // Find all linedefs that use this vertex.
  1028.                         CurrentVertex = Loop;
  1029.                         NoOfListObjects = 0;
  1030.                         if (LineDefPointer)
  1031.                         {
  1032.                             // Detect which lines need updating.
  1033.                             for (Loop2 = 0;Loop2 < LineDefPointer->NoOfObjects;Loop2++)
  1034.                             {
  1035.                                 if ((LineDefPointer->Data [Loop2].FromVertex == CurrentVertex) || (LineDefPointer->Data [Loop2].ToVertex == CurrentVertex))
  1036.                                 {
  1037.                                     ObjectList [NoOfListObjects] = Loop2;
  1038.                                     NoOfListObjects++;
  1039.                                 }
  1040.                             }
  1041.                         }
  1042.  
  1043.                         // Erase and delete the current linedefs. Work
  1044.                         // backwards to avoid indexes changing before we delete
  1045.                         // a line.
  1046.                         for (Loop2 = NoOfListObjects - 1;Loop2 >= 0;Loop2--)
  1047.                         {
  1048.                             DrawLineDef (DC,ObjectList [Loop2]);
  1049.                             LineDefPointer->Delete (ObjectList [Loop2]);
  1050.                         }
  1051.                 
  1052.                         // Erase object.
  1053.                         InvertRect (DC,&Rect);
  1054.                         VertexPointer->Delete (CurrentVertex);
  1055.                         
  1056.                         Done = TRUE;
  1057.                     }
  1058.                 }
  1059.                 
  1060.                 // Add a new vertex instead.
  1061.                 if (Done == FALSE)
  1062.                 {
  1063.                     // Add a new vertex taking gridsnap into account.
  1064.                     CurrentVertex = VertexPointer->Add (LOWORD (lParam) * Scale - OffsetX,-(HIWORD (lParam) * Scale + OffsetY));
  1065.                     SetRect (&Rect,(VertexPointer->Data [CurrentVertex].X + OffsetX) / Scale - VERTEX_SIZE,-(VertexPointer->Data [CurrentVertex].Y + OffsetY) / Scale - VERTEX_SIZE,(VertexPointer->Data [CurrentVertex].X + OffsetX) / Scale + VERTEX_SIZE,-(VertexPointer->Data [CurrentVertex].Y + OffsetY) / Scale + VERTEX_SIZE);
  1066.                     InvertRect (DC,&Rect);
  1067.                 }
  1068.                 
  1069.                 // Cleanup.
  1070.                 ReleaseDC (hWndMain,DC);
  1071.             }
  1072.         }
  1073.         break;
  1074.             
  1075.         case WM_LBUTTONDOWN:
  1076.         {
  1077.             int        Result;
  1078.             int        Loop;
  1079.             
  1080.             Result = FindThatVertex (LOWORD (lParam),HIWORD (lParam));
  1081.             if (Result != -1)
  1082.             {
  1083.                 // Set some global state variables.
  1084.                 CurrentVertex = Result;
  1085.                 MouseDown = TRUE;
  1086.  
  1087.                 // Now we narrow down the list of lines to update from this move.
  1088.                 NoOfListObjects = 0;
  1089.                 if (LineDefPointer)
  1090.                 {
  1091.                     // Detect which lines need updating.
  1092.                     for (Loop = 0;Loop < LineDefPointer->NoOfObjects;Loop++)
  1093.                     {
  1094.                         if ((LineDefPointer->Data [Loop].FromVertex == CurrentVertex) || (LineDefPointer->Data [Loop].ToVertex == CurrentVertex))
  1095.                         {
  1096.                             ObjectList [NoOfListObjects] = Loop;
  1097.                             NoOfListObjects++;
  1098.                         }
  1099.                     }
  1100.                 }
  1101.             }
  1102.         }
  1103.         break;
  1104.             
  1105.         case WM_LBUTTONUP:
  1106.             MoveMode = FALSE;
  1107.             MouseDown = FALSE;
  1108.             break;
  1109.     
  1110.         case WM_MOUSEMOVE: // Detect guys in chicks clothes (drags).
  1111.             if (MouseDown)
  1112.             {
  1113.                 int        Loop;
  1114.                 RECT    Rect;
  1115.                 HDC        DC;
  1116.                 
  1117.                 DC = GetDC (hWndMain);
  1118.                 SetROP2 (DC,R2_NOTMERGEPEN);
  1119.  
  1120.                 // Erase the vertex from the screen.
  1121.                 SetRect (&Rect,(VertexPointer->Data [CurrentVertex].X + OffsetX) / Scale - VERTEX_SIZE,-(VertexPointer->Data [CurrentVertex].Y + OffsetY) / Scale - VERTEX_SIZE,(VertexPointer->Data [CurrentVertex].X + OffsetX) / Scale + VERTEX_SIZE,-(VertexPointer->Data [CurrentVertex].Y + OffsetY) / Scale + VERTEX_SIZE);
  1122.                 InvertRect (DC,&Rect);
  1123.                 
  1124.                 // Erase the current linedefs.
  1125.                 for (Loop = 0;Loop < NoOfListObjects;Loop++)
  1126.                     DrawLineDef (DC,ObjectList [Loop]);
  1127.                 
  1128.                 // Update the vertex position.
  1129.                 VertexPointer->Data [CurrentVertex].X = LOWORD (lParam) * Scale - OffsetX;
  1130.                 VertexPointer->Data [CurrentVertex].Y = -(HIWORD (lParam) * Scale + OffsetY);
  1131.                 
  1132.                 // Take gridsnap int account.
  1133.                 if (GridSnap)
  1134.                 {
  1135.                     VertexPointer->Data [CurrentVertex].X -= VertexPointer->Data [CurrentVertex].X % GridSize;
  1136.                     VertexPointer->Data [CurrentVertex].Y -= VertexPointer->Data [CurrentVertex].Y % GridSize;
  1137.                 }
  1138.  
  1139.                 // Redraw the vertex.
  1140.                 SetRect (&Rect,(VertexPointer->Data [CurrentVertex].X + OffsetX) / Scale - VERTEX_SIZE,-(VertexPointer->Data [CurrentVertex].Y + OffsetY) / Scale - VERTEX_SIZE,(VertexPointer->Data [CurrentVertex].X + OffsetX) / Scale + VERTEX_SIZE,-(VertexPointer->Data [CurrentVertex].Y + OffsetY) / Scale + VERTEX_SIZE);
  1141.                 InvertRect (DC,&Rect);
  1142.                 
  1143.                 // Redraw all linedefs.
  1144.                 for (Loop = 0;Loop < NoOfListObjects;Loop++)
  1145.                     DrawLineDef (DC,ObjectList [Loop]);
  1146.  
  1147.                 ReleaseDC (hWndMain,DC);
  1148.                 MoveMode = TRUE;
  1149.             }
  1150.             break;
  1151.         
  1152.         default:
  1153.             return DefWindowProc (hWnd,Message,wParam,lParam);
  1154.     }
  1155.     
  1156.     return 0L;
  1157. }
  1158.  
  1159. // ╔════════════════════════════════════════════════════════════════════════╗
  1160. // ║                          LineDef Editing                               ║
  1161. // ║                                                                        ║
  1162. // ║ Pretty obvious.                                                        ║
  1163. // ╚════════════════════════════════════════════════════════════════════════╝
  1164.  
  1165. int FindThatLineDef (int X,int Y)
  1166. {
  1167.     int        Loop;
  1168.     int        MidX;
  1169.     int        MidY;
  1170.     long    DX;
  1171.     long    DY;
  1172.     long    Min = 1000000L;
  1173.     long    Value;
  1174.     int        Selected = -1;
  1175.  
  1176.     if (VertexPointer && LineDefPointer)
  1177.     {
  1178.         // Nearest to the centre of a linedef wins !
  1179.         for (Loop = 0;Loop < LineDefPointer->NoOfObjects;Loop++)
  1180.         {
  1181.             // Get the midpoints.
  1182.             MidX = (VertexPointer->Data [LineDefPointer->Data [Loop].FromVertex].X + VertexPointer->Data [LineDefPointer->Data [Loop].ToVertex].X) / 2;
  1183.             MidY = (VertexPointer->Data [LineDefPointer->Data [Loop].FromVertex].Y + VertexPointer->Data [LineDefPointer->Data [Loop].ToVertex].Y) / 2;
  1184.             
  1185.             // Work out distance from the midpoints.
  1186.             DX = (long) (MidX + OffsetX) / Scale - X;
  1187.             DY = (long) -(MidY + OffsetY) / Scale - Y;
  1188.             Value = DX * DX + DY * DY;
  1189.             if (Value < Min)
  1190.             {
  1191.                 Min = Value;
  1192.                 Selected = Loop;
  1193.             }
  1194.         }
  1195.     }
  1196.     
  1197.     return Selected;
  1198. }
  1199.  
  1200.  
  1201. BOOL FAR PASCAL SideDefProc (HWND hWndDlg, WORD Message, WORD wParam, LONG lParam)
  1202. {
  1203.     switch (Message)
  1204.     {
  1205.         case WM_INITDIALOG:
  1206.         {
  1207.             int        Loop;
  1208.             int        Loop2;
  1209.             char    Text [60];
  1210.             HANDLE    MemHandle;
  1211.             char *    MemPointer;
  1212.             int        FileHandle;
  1213.             int        NoOfTextures;
  1214.             
  1215.             // Open the main WAD file and check out the textures.
  1216.             FileHandle = open (DoomWadName,O_BINARY|O_RDONLY);
  1217.             if (FileHandle)
  1218.             {
  1219.                 for (Loop = 0;Loop < DoomHeader.NumberOfEntries;Loop++)
  1220.                 {
  1221.                     if (strncmp (DoomDirectory [Loop].ResourceName,"TEXTURE",7) == 0)
  1222.                     {
  1223.                         // One of the texture patch maps.
  1224.                         MemHandle = GlobalAlloc (GMEM_MOVEABLE,DoomDirectory [Loop].ResourceSize);
  1225.                         MemPointer = (char *) GlobalLock (MemHandle);
  1226.                         if (MemPointer)
  1227.                         {
  1228.                             lseek (FileHandle,DoomDirectory [Loop].ResourcePointer,SEEK_SET);
  1229.                             lread (FileHandle,MemPointer,DoomDirectory [Loop].ResourceSize);
  1230.  
  1231.                             // Put the strings into a list box.
  1232.                             Text [8] = '\000';
  1233.                             NoOfTextures = int (*(long *) MemPointer);
  1234.                             for (Loop2 = 0;Loop2 < NoOfTextures;Loop2++)
  1235.                             {
  1236.                                 strncpy (Text,MemPointer + long (*(long *) (MemPointer + 4L * long (Loop2 + 1))),8);
  1237.                                 SendDlgItemMessage (hWndDlg,10,CB_ADDSTRING,0,(LONG) Text);
  1238.                             }
  1239.  
  1240.                             // Free the memory.
  1241.                             GlobalUnlock (MemHandle);
  1242.                             GlobalFree (MemHandle);
  1243.                         }
  1244.                     }
  1245.                 }
  1246.                 close (FileHandle);
  1247.             }
  1248.             
  1249.             SendDlgItemMessage (hWndDlg,10,CB_SETCURSEL,0,0);
  1250.         }
  1251.            break;
  1252.             
  1253.         case REDRAW_MESSAGE: // Update the window.
  1254.         {
  1255.             // Update our display.
  1256.             if (SideDefPointer)
  1257.             {
  1258.                 if (SideDefPointer->NoOfObjects > 0)
  1259.                 {
  1260.                     int        LeftOn;
  1261.                     char    Text [20];
  1262.                     
  1263.                     // Only make these controls accessable when the left sidedef
  1264.                     // exists.
  1265.                     LeftOn = LineDefPointer->Data [CurrentLineDef].Sidedef2 >= 0;
  1266.                     EnableWindow (GetDlgItem (hWndDlg,11),LeftOn);
  1267.                     EnableWindow (GetDlgItem (hWndDlg,12),LeftOn);
  1268.                     EnableWindow (GetDlgItem (hWndDlg,22),LeftOn);
  1269.                     EnableWindow (GetDlgItem (hWndDlg,14),LeftOn);
  1270.                     EnableWindow (GetDlgItem (hWndDlg,15),LeftOn);
  1271.                     EnableWindow (GetDlgItem (hWndDlg,17),LeftOn);
  1272.                     EnableWindow (GetDlgItem (hWndDlg,18),LeftOn);
  1273.                     EnableWindow (GetDlgItem (hWndDlg,20),LeftOn);
  1274.                     EnableWindow (GetDlgItem (hWndDlg,21),LeftOn);
  1275.                     
  1276.                     // Fill in the right hand side.
  1277.                     SetDlgItemInt (hWndDlg,23,SideDefPointer->Data [CurrentRightDef].X,TRUE);
  1278.                     SetDlgItemInt (hWndDlg,24,SideDefPointer->Data [CurrentRightDef].Y,TRUE);
  1279.                     SetDlgItemInt (hWndDlg,34,SideDefPointer->Data [CurrentRightDef].Sector,TRUE);
  1280.                     Text [8] = '\000';
  1281.                     strncpy (Text,SideDefPointer->Data [CurrentRightDef].Above,8);
  1282.                     SetDlgItemText (hWndDlg,25,Text);
  1283.                     strncpy (Text,SideDefPointer->Data [CurrentRightDef].Wall,8);
  1284.                     SetDlgItemText (hWndDlg,28,Text);
  1285.                     strncpy (Text,SideDefPointer->Data [CurrentRightDef].Below,8);
  1286.                     SetDlgItemText (hWndDlg,31,Text);
  1287.                     
  1288.                     // Fill in the left hand side.
  1289.                     if (LineDefPointer->Data [CurrentLineDef].Sidedef2 >= 0)
  1290.                     {
  1291.                         SetDlgItemInt (hWndDlg,11,SideDefPointer->Data [CurrentLeftDef].X,TRUE);
  1292.                         SetDlgItemInt (hWndDlg,12,SideDefPointer->Data [CurrentLeftDef].Y,TRUE);
  1293.                         SetDlgItemInt (hWndDlg,22,SideDefPointer->Data [CurrentLeftDef].Sector,TRUE);
  1294.                         strncpy (Text,SideDefPointer->Data [CurrentLeftDef].Above,8);
  1295.                         SetDlgItemText (hWndDlg,13,Text);
  1296.                         strncpy (Text,SideDefPointer->Data [CurrentLeftDef].Wall,8);
  1297.                         SetDlgItemText (hWndDlg,16,Text);
  1298.                         strncpy (Text,SideDefPointer->Data [CurrentLeftDef].Below,8);
  1299.                         SetDlgItemText (hWndDlg,19,Text);
  1300.                     }
  1301.                     else
  1302.                     {
  1303.                         // Blank out the left side to avoid confusion.
  1304.                         SetDlgItemText (hWndDlg,11,"");
  1305.                         SetDlgItemText (hWndDlg,12,"");
  1306.                         SetDlgItemText (hWndDlg,22,"");
  1307.                         SetDlgItemText (hWndDlg,13,"");
  1308.                         SetDlgItemText (hWndDlg,16,"");
  1309.                         SetDlgItemText (hWndDlg,19,"");
  1310.                     }
  1311.                 }
  1312.             }
  1313.         }
  1314.         break;
  1315.         
  1316.         case WM_COMMAND:
  1317.         {
  1318.             int        Trans;
  1319.             char    Text [10];
  1320.             
  1321.             if (SideDefPointer)
  1322.             {
  1323.                 switch (wParam)
  1324.                    {
  1325.                        case 1: // Ok button.
  1326.                         ShowWindow (hWndSideDef,SW_HIDE);
  1327.                            break;
  1328.  
  1329.                     case 23: // X.
  1330.                         if (HIWORD (lParam) == EN_CHANGE)
  1331.                             SideDefPointer->Data [CurrentRightDef].X = GetDlgItemInt (hWndDlg,wParam,&Trans,TRUE);
  1332.                         break;
  1333.  
  1334.                     case 24: // Y.
  1335.                         if (HIWORD (lParam) == EN_CHANGE)
  1336.                             SideDefPointer->Data [CurrentRightDef].Y = GetDlgItemInt (hWndDlg,wParam,&Trans,TRUE);
  1337.                         break;
  1338.  
  1339.                     case 26: // Clear Above.
  1340.                         strcpy (SideDefPointer->Data [CurrentRightDef].Above,"-");
  1341.                         SetDlgItemText (hWndDlg,25,"-");
  1342.                         break;
  1343.  
  1344.                     case 27: // Set Above.
  1345.                         SendDlgItemMessage (hWndDlg,10,CB_GETLBTEXT,(WORD) SendDlgItemMessage (hWndDlg,10,CB_GETCURSEL,0,0),(LONG) Text);
  1346.                         strncpy (SideDefPointer->Data [CurrentRightDef].Above,Text,8);
  1347.                         SetDlgItemText (hWndDlg,25,Text);
  1348.                         break;
  1349.  
  1350.                     case 29: // Clear wall.
  1351.                         strcpy (SideDefPointer->Data [CurrentRightDef].Wall,"-");
  1352.                         SetDlgItemText (hWndDlg,28,"-");
  1353.                         break;
  1354.  
  1355.                     case 30: // Set wall.
  1356.                         SendDlgItemMessage (hWndDlg,10,CB_GETLBTEXT,(WORD) SendDlgItemMessage (hWndDlg,10,CB_GETCURSEL,0,0),(LONG) Text);
  1357.                         strncpy (SideDefPointer->Data [CurrentRightDef].Wall,Text,8);
  1358.                         SetDlgItemText (hWndDlg,28,Text);
  1359.                         break;
  1360.  
  1361.                     case 32: // Clear Below.
  1362.                         strcpy (SideDefPointer->Data [CurrentRightDef].Below,"-");
  1363.                         SetDlgItemText (hWndDlg,31,"-");
  1364.                         break;
  1365.  
  1366.                     case 33: // Set Below.
  1367.                         SendDlgItemMessage (hWndDlg,10,CB_GETLBTEXT,(WORD) SendDlgItemMessage (hWndDlg,10,CB_GETCURSEL,0,0),(LONG) Text);
  1368.                         strncpy (SideDefPointer->Data [CurrentRightDef].Below,Text,8);
  1369.                         SetDlgItemText (hWndDlg,31,Text);
  1370.                         break;
  1371.  
  1372.                     // These apply to the left sidedef.
  1373.                     case 11: // X.
  1374.                         if (HIWORD (lParam) == EN_CHANGE && LineDefPointer->Data [CurrentLineDef].Sidedef2 >= 0)
  1375.                             SideDefPointer->Data [CurrentLeftDef].X = GetDlgItemInt (hWndDlg,wParam,&Trans,TRUE);
  1376.                         break;
  1377.  
  1378.                     case 12: // Y.
  1379.                         if (HIWORD (lParam) == EN_CHANGE && LineDefPointer->Data [CurrentLineDef].Sidedef2 >= 0)
  1380.                             SideDefPointer->Data [CurrentLeftDef].Y = GetDlgItemInt (hWndDlg,wParam,&Trans,TRUE);
  1381.                         break;
  1382.  
  1383.                     case 14: // Clear Above.
  1384.                         if (LineDefPointer->Data [CurrentLineDef].Sidedef2 >= 0)
  1385.                         {
  1386.                             strcpy (SideDefPointer->Data [CurrentLeftDef].Above,"-");
  1387.                             SetDlgItemText (hWndDlg,13,"-");
  1388.                         }
  1389.                         break;
  1390.  
  1391.                     case 15: // Set Above.
  1392.                         if (LineDefPointer->Data [CurrentLineDef].Sidedef2 >= 0)
  1393.                         {
  1394.                             SendDlgItemMessage (hWndDlg,10,CB_GETLBTEXT,(WORD) SendDlgItemMessage (hWndDlg,10,CB_GETCURSEL,0,0),(LONG) Text);
  1395.                             strncpy (SideDefPointer->Data [CurrentLeftDef].Above,Text,8);
  1396.                             SetDlgItemText (hWndDlg,13,Text);
  1397.                         }
  1398.                         break;
  1399.  
  1400.                     case 17: // Clear wall.
  1401.                         if (LineDefPointer->Data [CurrentLineDef].Sidedef2 >= 0)
  1402.                         {
  1403.                             strcpy (SideDefPointer->Data [CurrentLeftDef].Wall,"-");
  1404.                             SetDlgItemText (hWndDlg,16,"-");
  1405.                         }
  1406.                         break;
  1407.  
  1408.                     case 18: // Set wall.
  1409.                         if (LineDefPointer->Data [CurrentLineDef].Sidedef2 >= 0)
  1410.                         {
  1411.                             SendDlgItemMessage (hWndDlg,10,CB_GETLBTEXT,(WORD) SendDlgItemMessage (hWndDlg,10,CB_GETCURSEL,0,0),(LONG) Text);
  1412.                             strncpy (SideDefPointer->Data [CurrentLeftDef].Wall,Text,8);
  1413.                             SetDlgItemText (hWndDlg,16,Text);
  1414.                         }
  1415.                         break;
  1416.  
  1417.                     case 20: // Clear Below.
  1418.                         if (LineDefPointer->Data [CurrentLineDef].Sidedef2 >= 0)
  1419.                         {
  1420.                             strcpy (SideDefPointer->Data [CurrentLeftDef].Below,"-");
  1421.                             SetDlgItemText (hWndDlg,19,"-");
  1422.                         }
  1423.                         break;
  1424.  
  1425.                     case 21: // Set Below.
  1426.                         if (LineDefPointer->Data [CurrentLineDef].Sidedef2 >= 0)
  1427.                         {
  1428.                             SendDlgItemMessage (hWndDlg,10,CB_GETLBTEXT,(WORD) SendDlgItemMessage (hWndDlg,10,CB_GETCURSEL,0,0),(LONG) Text);
  1429.                             strncpy (SideDefPointer->Data [CurrentLeftDef].Below,Text,8);
  1430.                             SetDlgItemText (hWndDlg,19,Text);
  1431.                         }
  1432.                         break;
  1433.                    }
  1434.                }
  1435.         }
  1436.         break;
  1437.  
  1438.         default:
  1439.             return FALSE;
  1440.     }
  1441.     return TRUE;
  1442. }
  1443.  
  1444.  
  1445. BOOL FAR PASCAL LineDefProc (HWND hWndDlg, WORD Message, WORD wParam, LONG lParam)
  1446. {
  1447.     switch (Message)
  1448.     {
  1449.         case WM_INITDIALOG:
  1450.         {
  1451.             fstream        InActivityFile;
  1452.             char        Buffer [BUFFER_SIZE];
  1453.             char        Text [BUFFER_SIZE];
  1454.             int            LineType;
  1455.             char *        CopyFrom;
  1456.                     
  1457.             // Load info into the special dialog box.
  1458.             InActivityFile.open ("GDREDIT.INI",ios::in|ios::nocreate);
  1459.             if (!InActivityFile.fail ())
  1460.             {
  1461.                 // Get to the start of the section we want.
  1462.                 do
  1463.                 {
  1464.                     InActivityFile.getline (Buffer,BUFFER_SIZE);
  1465.                 } while (!InActivityFile.eof () && strcmp (Buffer,"[LINETYPES]") != 0);
  1466.                 InActivityFile.getline (Buffer,BUFFER_SIZE);
  1467.                 
  1468.                 while (!InActivityFile.eof () && Buffer [0] != '[')
  1469.                 {
  1470.                     if (strlen (Buffer) > 0)
  1471.                     {
  1472.                         LineType = atoi (Buffer);
  1473.                         CopyFrom = strstr (Buffer,",");
  1474.                         if (CopyFrom != NULL)
  1475.                             strcpy (Text,CopyFrom + 1);
  1476.                         SendDlgItemMessage (hWndDlg,10,CB_SETITEMDATA,(WORD) SendDlgItemMessage (hWndDlg,10,CB_ADDSTRING,0,(LONG) Text),(LONG) LineType);
  1477.                     }
  1478.                 
  1479.                     InActivityFile.getline (Buffer,BUFFER_SIZE);
  1480.                 }
  1481.                 InActivityFile.close ();
  1482.             }
  1483.             SendDlgItemMessage (hWndDlg,10,CB_SETCURSEL,0,0);
  1484.         }
  1485.            break;
  1486.             
  1487.         case REDRAW_MESSAGE: // Update the window.
  1488.         {
  1489.             int        Loop;
  1490.             int        Finished = FALSE;
  1491.             int        Entry = -1;
  1492.             int        MaxTypes;
  1493.             
  1494.             // Update our display.
  1495.             if (LineDefPointer  && CurrentLineDef >= 0)
  1496.             {
  1497.                 // Set up the line type item.
  1498.                 MaxTypes = (int) SendDlgItemMessage (hWndDlg,10,CB_GETCOUNT,0,0);
  1499.                 Loop = -1;
  1500.                 do
  1501.                 {
  1502.                     Loop++;
  1503.                     if (SendDlgItemMessage (hWndDlg,10,CB_GETITEMDATA,Loop,0) == LineDefPointer->Data [CurrentLineDef].Types)
  1504.                     {
  1505.                         Finished = TRUE;
  1506.                         Entry = Loop;
  1507.                     }
  1508.                 } while (!Finished && Loop < MaxTypes);
  1509.                 SendDlgItemMessage (hWndDlg,10,CB_SETCURSEL,Entry,0);
  1510.                     
  1511.                 // Set up the bitsets.
  1512.                 CheckDlgButton (hWndDlg,11,LineDefPointer->Data [CurrentLineDef].Bitset & 1);
  1513.                 CheckDlgButton (hWndDlg,12,LineDefPointer->Data [CurrentLineDef].Bitset & 2);
  1514.                 CheckDlgButton (hWndDlg,13,LineDefPointer->Data [CurrentLineDef].Bitset & 4);
  1515.                 CheckDlgButton (hWndDlg,14,LineDefPointer->Data [CurrentLineDef].Bitset & 8);
  1516.                 CheckDlgButton (hWndDlg,15,LineDefPointer->Data [CurrentLineDef].Bitset & 16);
  1517.                 CheckDlgButton (hWndDlg,16,LineDefPointer->Data [CurrentLineDef].Bitset & 32);
  1518.                 CheckDlgButton (hWndDlg,17,LineDefPointer->Data [CurrentLineDef].Bitset & 64);
  1519.                 CheckDlgButton (hWndDlg,18,LineDefPointer->Data [CurrentLineDef].Bitset & 128);
  1520.                 CheckDlgButton (hWndDlg,19,LineDefPointer->Data [CurrentLineDef].Bitset & 256);
  1521.  
  1522.                 // Set up the edit fields.
  1523.                 SetDlgItemInt (hWndDlg,20,LineDefPointer->Data [CurrentLineDef].Trigger,TRUE);
  1524.                     
  1525.                 // Set up the sidedefs.
  1526.                 CurrentRightDef = LineDefPointer->Data [CurrentLineDef].Sidedef1;
  1527.                 CurrentLeftDef = LineDefPointer->Data [CurrentLineDef].Sidedef2;
  1528.                 SendMessage (hWndSideDef,REDRAW_MESSAGE,0,0L);
  1529.             }
  1530.         }
  1531.         break;
  1532.         
  1533.         case WM_COMMAND:
  1534.         {
  1535.             int        Trans;
  1536.             
  1537.             if (LineDefPointer && CurrentLineDef >= 0)
  1538.             {
  1539.                 switch (wParam)
  1540.                    {
  1541.                        case 1: // Ok button.
  1542.                         ShowWindow (hWndLineDef,SW_HIDE);
  1543.                            break;
  1544.  
  1545.                     case 10: // Line type changed.
  1546.                         if (HIWORD (lParam) == CBN_SELCHANGE)
  1547.                             LineDefPointer->Data [CurrentLineDef].Types = (int) SendDlgItemMessage (hWndDlg,wParam,CB_GETITEMDATA,(WORD) SendDlgItemMessage (hWndDlg,wParam,CB_GETCURSEL,0,0),0);
  1548.                         break;
  1549.                         
  1550.                     case 11: // Impassable line.
  1551.                     case 12: // Monsters can't cross.
  1552.                     case 13: // Two sided.
  1553.                     case 14: // Above unpegged.
  1554.                     case 15: // Below unpegged.
  1555.                     case 16: // Secret wall.
  1556.                     case 17: // Soundproof wall.
  1557.                     case 18: // Unmappable.
  1558.                     case 19: // Mapped at start of game.
  1559.                     {
  1560.                         int        Toggle = 1 << (wParam - 11);
  1561.                         
  1562.                         // We can toggle the state of the bitset by use of
  1563.                         // some maths.
  1564.                         if (LineDefPointer->Data [CurrentLineDef].Bitset & Toggle)
  1565.                             LineDefPointer->Data [CurrentLineDef].Bitset -= Toggle;
  1566.                         else
  1567.                             LineDefPointer->Data [CurrentLineDef].Bitset += Toggle;
  1568.                     }
  1569.                     break;
  1570.  
  1571.                     case 20: // Trigger.
  1572.                         if (HIWORD (lParam) == EN_CHANGE)
  1573.                             LineDefPointer->Data [CurrentLineDef].Trigger = GetDlgItemInt (hWndDlg,wParam,&Trans,TRUE);
  1574.                         break;
  1575.  
  1576.                     case 21: // Edit the sidedefs.
  1577.                         ShowWindow (hWndSideDef,SW_SHOW);
  1578.                         break;
  1579.                    }
  1580.                }
  1581.         }
  1582.         break;
  1583.  
  1584.         default:
  1585.             return FALSE;
  1586.     }
  1587.     return TRUE;
  1588. }
  1589.  
  1590.  
  1591. LONG FAR PASCAL LineDefEdit (HWND hWnd, WORD Message, WORD wParam, LONG lParam)
  1592. {
  1593.     switch (Message)
  1594.     {
  1595.         case WM_LBUTTONDOWN:
  1596.         {
  1597.             int        Result;
  1598.             HDC        DC;
  1599.             
  1600.             if (LineDefAddMode)
  1601.             {
  1602.                 if (LineDefPointer)
  1603.                 {
  1604.                     // Add new linedefs.
  1605.                     FromVertex = ToVertex;
  1606.                     ToVertex = FindThatVertex (LOWORD (lParam),HIWORD (lParam));
  1607.                     if (FromVertex >= 0 && ToVertex >= 0)
  1608.                     {
  1609.                         // We got one! Add it on.
  1610.                         CurrentLineDef = LineDefPointer->Add (FromVertex,ToVertex);
  1611.                         if (CurrentLineDef >= 0)
  1612.                         {
  1613.                             DC = GetDC (hWndMain);
  1614.                             SelectObject (DC,RedPen);
  1615.                             DrawLineDef (DC,CurrentLineDef);
  1616.                             SelectObject (DC,GetStockObject (BLACK_PEN));
  1617.                             ReleaseDC (hWndMain,DC);
  1618.                         }
  1619.                     }
  1620.                 }
  1621.             }
  1622.             else
  1623.             {
  1624.                 // Change the selected linedef.
  1625.                 Result = FindThatLineDef (LOWORD (lParam),HIWORD (lParam));
  1626.                 if (Result != -1)
  1627.                 {
  1628.                     HDC        DC;
  1629.                 
  1630.                     //  Set up for some drawing.
  1631.                     DC = GetDC (hWndMain);
  1632.                 
  1633.                     // Erase old highlighted linedef.
  1634.                     if (CurrentLineDef >= 0)
  1635.                     {
  1636.                         SelectObject (DC,YellowPen);
  1637.                         DrawLineDef (DC,CurrentLineDef);
  1638.                     }
  1639.                 
  1640.                     // Draw the new linedef.
  1641.                     CurrentLineDef = Result;
  1642.                     SelectObject (DC,RedPen);
  1643.                     DrawLineDef (DC,CurrentLineDef);
  1644.                         
  1645.                     // Clean up after drawing.
  1646.                     SelectObject (DC,GetStockObject (BLACK_PEN));
  1647.                     ReleaseDC (hWndMain,DC);
  1648.                     SendMessage (hWndLineDef,REDRAW_MESSAGE,0,0L);
  1649.                 }
  1650.             }
  1651.         }
  1652.         break;
  1653.  
  1654.         case WM_LBUTTONDBLCLK:
  1655.             ShowWindow (hWndLineDef,SW_SHOW);
  1656.             break;
  1657.             
  1658.         case ADD_MESSAGE:
  1659.         {
  1660.             HDC        DC;
  1661.             
  1662.             // Set up for the line drawing.
  1663.             LineDefAddMode = TRUE;
  1664.             LastLineDef = CurrentLineDef;
  1665.             FromVertex = -1;
  1666.             ToVertex = -1;
  1667.                 
  1668.             // Erase old highlighted linedef if it exists.
  1669.             if (CurrentLineDef >= 0)
  1670.             {
  1671.                 DC = GetDC (hWndMain);
  1672.                 SelectObject (DC,YellowPen);
  1673.                 DrawLineDef (DC,CurrentLineDef);
  1674.                 SelectObject (DC,GetStockObject (BLACK_PEN));
  1675.                 ReleaseDC (hWndMain,DC);
  1676.             }
  1677.         }
  1678.         break;
  1679.         
  1680.         case WM_RBUTTONDOWN: // Add mode off.
  1681.         {
  1682.             HDC        DC;
  1683.             int        Loop;
  1684.             
  1685.             //  Set up for some drawing.
  1686.             DC = GetDC (hWndMain);
  1687.                 
  1688.             // Remove red pen highlights except for the last item.
  1689.             SelectObject (DC,YellowPen);
  1690.             if (LastLineDef >= 0)
  1691.             {
  1692.                 for (Loop = LastLineDef;Loop < LineDefPointer->NoOfObjects - 1;Loop++)
  1693.                     DrawLineDef (DC,Loop);
  1694.             }
  1695.             
  1696.             // Clean up after drawing.
  1697.             SelectObject (DC,GetStockObject (BLACK_PEN));
  1698.             ReleaseDC (hWndMain,DC);
  1699.             LineDefAddMode = FALSE;
  1700.             LastLineDef = -1;
  1701.         }
  1702.         break;
  1703.         
  1704.         case DELETE_MESSAGE:
  1705.             if (CurrentLineDef >= 0)
  1706.             {
  1707.                 HDC        DC;
  1708.                 
  1709.                 // Setup time.
  1710.                 DC = GetDC (hWndMain);
  1711.                 
  1712.                 // Erase and delete the current linedef.
  1713.                 SelectObject (DC,BluePen);
  1714.                 DrawLineDef (DC,CurrentLineDef);
  1715.                 LineDefPointer->Delete (CurrentLineDef);
  1716.                 
  1717.                 // We can switch to another line now.
  1718.                 CurrentLineDef--;
  1719.                 if (CurrentLineDef < 0)
  1720.                     CurrentLineDef = LineDefPointer->NoOfObjects - 1;
  1721.                 
  1722.                 // Highlight the linedef we switched to.
  1723.                 if (CurrentLineDef >= 0)
  1724.                 {
  1725.                     SelectObject (DC,RedPen);
  1726.                     DrawLineDef (DC,CurrentLineDef);
  1727.                 }
  1728.  
  1729.                 // Clean up.
  1730.                 SelectObject (DC,GetStockObject (BLACK_PEN));
  1731.                 ReleaseDC (hWndMain,DC);
  1732.             }
  1733.             break;
  1734.         
  1735.         default:
  1736.             return DefWindowProc (hWnd,Message,wParam,lParam);
  1737.     }
  1738.     
  1739.     return 0L;
  1740. }
  1741.  
  1742. // ╔════════════════════════════════════════════════════════════════════════╗
  1743. // ║                           Sector Editing                               ║
  1744. // ║                                                                        ║
  1745. // ║ The edit procedure makes heavy use of the "ObjectList" to store the    ║
  1746. // ║ lines for the current sector. Be sure this list always contains the    ║
  1747. // ║ correct information.                                                   ║
  1748. // ╚════════════════════════════════════════════════════════════════════════╝
  1749.  
  1750. BOOL FAR PASCAL SectorProc (HWND hWndDlg, WORD Message, WORD wParam, LONG lParam)
  1751. {
  1752.     switch (Message)
  1753.     {
  1754.         case WM_INITDIALOG:
  1755.         {
  1756.             fstream        InActivityFile;
  1757.             char        Buffer [BUFFER_SIZE];
  1758.             char        Text [BUFFER_SIZE];
  1759.             int            ItemType;
  1760.             char *        CopyFrom;
  1761.             int            Loop;
  1762.             int            Add = FALSE;
  1763.                     
  1764.             // Load info into the special dialog box.
  1765.             InActivityFile.open ("GDREDIT.INI",ios::in|ios::nocreate);
  1766.             if (!InActivityFile.fail ())
  1767.             {
  1768.                 // Get to the start of the section we want.
  1769.                 do
  1770.                 {
  1771.                     InActivityFile.getline (Buffer,BUFFER_SIZE);
  1772.                 } while (!InActivityFile.eof () && strcmp (Buffer,"[SPECIAL]") != 0);
  1773.                 InActivityFile.getline (Buffer,BUFFER_SIZE);
  1774.                 
  1775.                 while (!InActivityFile.eof () && Buffer [0] != '[')
  1776.                 {
  1777.                     if (strlen (Buffer) > 0)
  1778.                     {
  1779.                         ItemType = atoi (Buffer);
  1780.                         CopyFrom = strstr (Buffer,",");
  1781.                         if (CopyFrom != NULL)
  1782.                             strcpy (Text,CopyFrom + 1);
  1783.                         SendDlgItemMessage (hWndDlg,16,CB_SETITEMDATA,(WORD) SendDlgItemMessage (hWndDlg,16,CB_ADDSTRING,0,(LONG) Text),(LONG) ItemType);
  1784.                     }
  1785.                 
  1786.                     InActivityFile.getline (Buffer,BUFFER_SIZE);
  1787.                 }
  1788.                 InActivityFile.close ();
  1789.             }
  1790.             
  1791.             // Load the floor and ceiling textures.
  1792.             Text [8] = '\000';
  1793.             for (Loop = 0;Loop < DoomHeader.NumberOfEntries;Loop++)
  1794.             {
  1795.                 if (strncmp (DoomDirectory [Loop].ResourceName,"F_END",8) == 0)
  1796.                     Add = FALSE;
  1797.                     
  1798.                 if (Add && strncmp (DoomDirectory [Loop].ResourceName,"F1",2) != 0 && strncmp (DoomDirectory [Loop].ResourceName,"F2",2) != 0)
  1799.                 {
  1800.                     strncpy (Text,DoomDirectory [Loop].ResourceName,8);
  1801.                     SendDlgItemMessage (hWndDlg,14,CB_ADDSTRING,0,(LONG) Text);
  1802.                     SendDlgItemMessage (hWndDlg,15,CB_ADDSTRING,0,(LONG) Text);
  1803.                 }
  1804.                 
  1805.                 if (strncmp (DoomDirectory [Loop].ResourceName,"F_START",8) == 0)
  1806.                     Add = TRUE;
  1807.             }
  1808.             
  1809.             SendDlgItemMessage (hWndDlg,10,CB_SETCURSEL,0,0);
  1810.         }
  1811.            break;
  1812.             
  1813.         case REDRAW_MESSAGE: // Update the window.
  1814.         {
  1815.             int        Loop;
  1816.             int        Finished = FALSE;
  1817.             int        Entry = -1;
  1818.             char    Text [20];
  1819.             int        MaxTypes;
  1820.             
  1821.             // Update our display.
  1822.             if (SectorPointer && CurrentSector >= 0)
  1823.             {
  1824.                 // Set up the special item.
  1825.                 MaxTypes = (int) SendDlgItemMessage (hWndDlg,16,CB_GETCOUNT,0,0);
  1826.                 Loop = -1;
  1827.                 do
  1828.                 {
  1829.                     Loop++;
  1830.                     if (SendDlgItemMessage (hWndDlg,16,CB_GETITEMDATA,Loop,0) == SectorPointer->Data [CurrentSector].Special)
  1831.                     {
  1832.                         Finished = TRUE;
  1833.                         Entry = Loop;
  1834.                     }
  1835.                 } while (!Finished && Loop < MaxTypes);
  1836.                 SendDlgItemMessage (hWndDlg,16,CB_SETCURSEL,Entry,0);
  1837.                     
  1838.                 // Set up the edit fields.
  1839.                 SetDlgItemInt (hWndDlg,10,SectorPointer->Data [CurrentSector].FloorHeight,TRUE);
  1840.                 SetDlgItemInt (hWndDlg,11,SectorPointer->Data [CurrentSector].CeilingHeight,TRUE);
  1841.                 SetDlgItemInt (hWndDlg,12,SectorPointer->Data [CurrentSector].Brightness,TRUE);
  1842.                 SetDlgItemInt (hWndDlg,13,SectorPointer->Data [CurrentSector].Trigger,TRUE);
  1843.                     
  1844.                 // Now set the list boxes.
  1845.                 Text [8] = '\000';
  1846.                 strncpy (Text,SectorPointer->Data [CurrentSector].FloorTexture,8);
  1847.                 Entry = (int) SendDlgItemMessage (hWndDlg,14,CB_FINDSTRING,0,(LONG) Text);
  1848.                 SendDlgItemMessage (hWndDlg,14,CB_SETCURSEL,Entry,0);
  1849.                 strncpy (Text,SectorPointer->Data [CurrentSector].CeilingTexture,8);
  1850.                 Entry = (int) SendDlgItemMessage (hWndDlg,15,CB_FINDSTRING,0,(LONG) Text);
  1851.                 SendDlgItemMessage (hWndDlg,15,CB_SETCURSEL,Entry,0);
  1852.             }
  1853.         }
  1854.         break;
  1855.         
  1856.         case WM_COMMAND:
  1857.         {
  1858.             int        Trans;
  1859.             char    Text [20];
  1860.             
  1861.             if (SectorPointer && CurrentSector >= 0)
  1862.             {
  1863.                 switch (wParam)
  1864.                    {
  1865.                     case 10: // Floor Height.
  1866.                         if (HIWORD (lParam) == EN_CHANGE)
  1867.                             SectorPointer->Data [CurrentSector].FloorHeight = GetDlgItemInt (hWndDlg,10,&Trans,TRUE);
  1868.                         break;
  1869.  
  1870.                     case 11: // Ceiling Height.
  1871.                         if (HIWORD (lParam) == EN_CHANGE)
  1872.                             SectorPointer->Data [CurrentSector].CeilingHeight = GetDlgItemInt (hWndDlg,11,&Trans,TRUE);
  1873.                         break;
  1874.  
  1875.                     case 12: // Sector brightness changed.
  1876.                         if (HIWORD (lParam) == EN_CHANGE)
  1877.                             SectorPointer->Data [CurrentSector].Brightness = GetDlgItemInt (hWndDlg,12,&Trans,TRUE);
  1878.                         break;
  1879.  
  1880.                     case 13: // Trigger has changed.
  1881.                         if (HIWORD (lParam) == EN_CHANGE)
  1882.                             SectorPointer->Data [CurrentSector].Trigger = GetDlgItemInt (hWndDlg,13,&Trans,TRUE);
  1883.                         break;
  1884.  
  1885.                     case 14: // Floor texture has changed.
  1886.                         if (HIWORD (lParam) == CBN_SELCHANGE)
  1887.                         {
  1888.                             SendDlgItemMessage (hWndDlg,14,CB_GETLBTEXT,(WORD) SendDlgItemMessage (hWndDlg,14,CB_GETCURSEL,0,0),(LONG) Text);
  1889.                             strncpy (SectorPointer->Data [CurrentSector].FloorTexture,Text,8);
  1890.                         }
  1891.                         break;
  1892.  
  1893.                     case 15: // Ceiling texture has changed.
  1894.                         if (HIWORD (lParam) == CBN_SELCHANGE)
  1895.                         {
  1896.                             SendDlgItemMessage (hWndDlg,15,CB_GETLBTEXT,(WORD) SendDlgItemMessage (hWndDlg,15,CB_GETCURSEL,0,0),(LONG) Text);
  1897.                             strncpy (SectorPointer->Data [CurrentSector].CeilingTexture,Text,8);
  1898.                         }
  1899.                         break;
  1900.  
  1901.                     case 16: // Special info changed.
  1902.                         if (HIWORD (lParam) == CBN_SELCHANGE)
  1903.                             SectorPointer->Data [CurrentSector].Special = (int) SendDlgItemMessage (hWndDlg,16,CB_GETITEMDATA,(WORD) SendDlgItemMessage (hWndDlg,16,CB_GETCURSEL,0,0),0);
  1904.                         break;
  1905.                    }
  1906.                }
  1907.         }
  1908.         break;
  1909.         default:
  1910.             return FALSE;
  1911.     }
  1912.     return TRUE;
  1913. }
  1914.  
  1915.  
  1916. LONG FAR PASCAL SectorEdit (HWND hWnd, WORD Message, WORD wParam, LONG lParam)
  1917. {
  1918.     switch (Message)
  1919.     {
  1920.         case WM_LBUTTONDOWN:
  1921.         {
  1922.             int        Result;
  1923.             int        Loop;
  1924.             
  1925.             if (SectorAddMode)
  1926.             {
  1927.                 if (LineDefPointer)
  1928.                 {
  1929.                     // Add new linedefs.
  1930.                     FromVertex = ToVertex;
  1931.                     ToVertex = FindThatVertex (LOWORD (lParam),HIWORD (lParam));
  1932.                     if (FromVertex >= 0 && ToVertex >= 0)
  1933.                     {
  1934.                         HDC        DC;
  1935.                 
  1936.                         //  Set up for some drawing.
  1937.                         DC = GetDC (hWndMain);
  1938.                         SelectObject (DC,RedPen);
  1939.                         
  1940.                         // Check for a linedef.
  1941.                         for (Loop = 0;Loop < LineDefPointer->NoOfObjects;Loop++)
  1942.                         {
  1943.                             // Place the sector on the right sidedef.
  1944.                             if ((LineDefPointer->Data [Loop].FromVertex == FromVertex) && (LineDefPointer->Data [Loop].ToVertex == ToVertex))
  1945.                             {
  1946.                                 // Select this line and display.
  1947.                                 CurrentLineDef = Loop;
  1948.                                 DrawLineDef (DC,CurrentLineDef);
  1949.  
  1950.                                 // Create a new sidedef if needed.
  1951.                                 if (LineDefPointer->Data [Loop].Sidedef1 < 0)
  1952.                                     LineDefPointer->Data [Loop].Sidedef1 = SideDefPointer->Add ();
  1953.                                 SideDefPointer->Data [LineDefPointer->Data [Loop].Sidedef1].Sector = CurrentSector;
  1954.                             }
  1955.                             
  1956.                             // Place the sector on the left sidedef.
  1957.                             if ((LineDefPointer->Data [Loop].ToVertex == FromVertex) && (LineDefPointer->Data [Loop].FromVertex == ToVertex))
  1958.                             {
  1959.                                 // Select this line and display.
  1960.                                 CurrentLineDef = Loop;
  1961.                                 DrawLineDef (DC,CurrentLineDef);
  1962.                                 
  1963.                                 // Create a new sidedef if needed.
  1964.                                 if (LineDefPointer->Data [Loop].Sidedef2 < 0)
  1965.                                     LineDefPointer->Data [Loop].Sidedef2 = SideDefPointer->Add ();
  1966.                                 SideDefPointer->Data [LineDefPointer->Data [Loop].Sidedef2].Sector = CurrentSector;
  1967.                             }
  1968.                         }
  1969.  
  1970.                         // Clean up after drawing.
  1971.                         SelectObject (DC,GetStockObject (BLACK_PEN));
  1972.                         ReleaseDC (hWndMain,DC);
  1973.                     }
  1974.                 }
  1975.             }
  1976.             else
  1977.             {
  1978.                 Result = FindThatLineDef (LOWORD (lParam),HIWORD (lParam));
  1979.                 if (Result != -1)
  1980.                 {
  1981.                     HDC        DC;
  1982.                 
  1983.                     //  Set up for some drawing.
  1984.                     DC = GetDC (hWndMain);
  1985.                 
  1986.                     // Get ready to update the dialog.
  1987.                     CurrentLineDef = Result;
  1988.                     if (CurrentLineDef == LastLineDef)
  1989.                         if (UseSide1 && LineDefPointer->Data [CurrentLineDef].Sidedef2 >= 0)
  1990.                             UseSide1 = FALSE;
  1991.                         else
  1992.                             UseSide1 = TRUE;
  1993.                     else
  1994.                         UseSide1 = TRUE;
  1995.  
  1996.                     // Select the sector from the linedef.
  1997.                     if (UseSide1)
  1998.                         CurrentSector = SideDefPointer->Data [LineDefPointer->Data [CurrentLineDef].Sidedef1].Sector;
  1999.                     else
  2000.                         CurrentSector = SideDefPointer->Data [LineDefPointer->Data [CurrentLineDef].Sidedef2].Sector;
  2001.                         
  2002.                     SendMessage (hWndSector,REDRAW_MESSAGE,0,0L);
  2003.  
  2004.                     // Erase the sector.
  2005.                     if (SectorOn)
  2006.                     {
  2007.                         SelectObject (DC,YellowPen);
  2008.                         for (Loop = 0;Loop < NoOfListObjects;Loop++)
  2009.                             DrawLineDef (DC,ObjectList [Loop]);
  2010.                     }
  2011.                 
  2012.                     // Possible for no sector to be defined for a linedef.
  2013.                     if (CurrentSector >= 0)
  2014.                     {
  2015.                         SectorOn = TRUE;
  2016.                         NoOfListObjects = 0;
  2017.                         SelectObject (DC,RedPen);
  2018.                         for (Loop = 0;Loop < LineDefPointer->NoOfObjects;Loop++)
  2019.                         {
  2020.                             // Right hand sides. These MUST exist for each linedef.
  2021.                             if (SideDefPointer->Data [LineDefPointer->Data [Loop].Sidedef1].Sector == CurrentSector)
  2022.                             {
  2023.                                 ObjectList [NoOfListObjects] = Loop;
  2024.                                 NoOfListObjects++;
  2025.                             }
  2026.  
  2027.                             // Left hand sides are optional.
  2028.                             if (LineDefPointer->Data [Loop].Sidedef2 >= 0)
  2029.                             {
  2030.                                 if (SideDefPointer->Data [LineDefPointer->Data [Loop].Sidedef2].Sector == CurrentSector)
  2031.                                 {
  2032.                                     ObjectList [NoOfListObjects] = Loop;
  2033.                                     NoOfListObjects++;
  2034.                                 }
  2035.                             }
  2036.                         }
  2037.  
  2038.                         // Draw the sector.
  2039.                         for (Loop = 0;Loop < NoOfListObjects;Loop++)
  2040.                             DrawLineDef (DC,ObjectList [Loop]);
  2041.                     }
  2042.     
  2043.                     // Clean up after drawing.
  2044.                     SelectObject (DC,GetStockObject (BLACK_PEN));
  2045.                     ReleaseDC (hWndMain,DC);
  2046.                     LastLineDef = CurrentLineDef;
  2047.                 }
  2048.             }
  2049.         }
  2050.         break;
  2051.  
  2052.         case ADD_MESSAGE:
  2053.         {
  2054.             HDC        DC;
  2055.             int        Loop;
  2056.             
  2057.             //  Set up for some drawing.
  2058.             DC = GetDC (hWndMain);
  2059.  
  2060.             // Erase the current sector.
  2061.             if (CurrentSector >= 0)
  2062.             {
  2063.                 SelectObject (DC,YellowPen);
  2064.                 for (Loop = 0;Loop < NoOfListObjects;Loop++)
  2065.                     DrawLineDef (DC,ObjectList [Loop]);
  2066.             }
  2067.     
  2068.             // Add the sector and prepare to draw the lines.
  2069.             CurrentSector = SectorPointer->Add ();
  2070.             SectorAddMode = TRUE;
  2071.             FromVertex = -1;
  2072.             ToVertex = -1;
  2073.             
  2074.             // Clean up after drawing.
  2075.             SelectObject (DC,GetStockObject (BLACK_PEN));
  2076.             ReleaseDC (hWndMain,DC);
  2077.         }
  2078.         break;
  2079.         
  2080.         case WM_RBUTTONDOWN: // Add mode off.
  2081.         {
  2082.             int        Loop;
  2083.             
  2084.             // Turn off the useful globals.
  2085.             SectorAddMode = FALSE;
  2086.             
  2087.             // We want to update the list for the new sector to be erased.
  2088.             if (CurrentSector >= 0)
  2089.             {
  2090.                 SectorOn = TRUE;
  2091.                 NoOfListObjects = 0;
  2092.                 for (Loop = 0;Loop < LineDefPointer->NoOfObjects;Loop++)
  2093.                 {
  2094.                     // Right hand sides. These MUST exist for each linedef.
  2095.                     if (SideDefPointer->Data [LineDefPointer->Data [Loop].Sidedef1].Sector == CurrentSector)
  2096.                     {
  2097.                         ObjectList [NoOfListObjects] = Loop;
  2098.                         NoOfListObjects++;
  2099.                     }
  2100.  
  2101.                     // Left hand sides are optional.
  2102.                     if (LineDefPointer->Data [Loop].Sidedef2 >= 0)
  2103.                     {
  2104.                         if (SideDefPointer->Data [LineDefPointer->Data [Loop].Sidedef2].Sector == CurrentSector)
  2105.                         {
  2106.                             ObjectList [NoOfListObjects] = Loop;
  2107.                             NoOfListObjects++;
  2108.                         }
  2109.                     }
  2110.                 }
  2111.             }
  2112.         }
  2113.         break;
  2114.         
  2115.         case DELETE_MESSAGE:
  2116.             if (CurrentSector >= 0)
  2117.             {
  2118.                 HDC        DC;
  2119.                 int        Loop;
  2120.                 
  2121.                 // Setup time.
  2122.                 DC = GetDC (hWndMain);
  2123.                 
  2124.                 // Erase the sector.
  2125.                 SelectObject (DC,YellowPen);
  2126.                 for (Loop = 0;Loop < NoOfListObjects;Loop++)
  2127.                     DrawLineDef (DC,ObjectList [Loop]);
  2128.                 SectorPointer->Delete (CurrentSector);
  2129.                 NoOfListObjects = 0;
  2130.  
  2131.                 // Switch to the next sector.
  2132.                 CurrentSector--;
  2133.                 if (CurrentSector < 0)
  2134.                     CurrentSector = SectorPointer->NoOfObjects - 1;
  2135.                 CurrentLineDef = -1;
  2136.                 LastLineDef = -1;
  2137.                     
  2138.                 // Draw the next sector if it exists.
  2139.                 if (CurrentSector >= 0)
  2140.                 {
  2141.                     // Work out who appears in the new sector.
  2142.                     for (Loop = 0;Loop < LineDefPointer->NoOfObjects;Loop++)
  2143.                     {
  2144.                         // Right hand sides. These MUST exist for each linedef.
  2145.                         if (SideDefPointer->Data [LineDefPointer->Data [Loop].Sidedef1].Sector == CurrentSector)
  2146.                         {
  2147.                             ObjectList [NoOfListObjects] = Loop;
  2148.                             NoOfListObjects++;
  2149.                         }
  2150.  
  2151.                         // Left hand sides are optional.
  2152.                         if (LineDefPointer->Data [Loop].Sidedef2 >= 0)
  2153.                         {
  2154.                             if (SideDefPointer->Data [LineDefPointer->Data [Loop].Sidedef2].Sector == CurrentSector)
  2155.                             {
  2156.                                 ObjectList [NoOfListObjects] = Loop;
  2157.                                 NoOfListObjects++;
  2158.                             }
  2159.                         }
  2160.                     }
  2161.                 
  2162.                     // Draw the lines.
  2163.                     SelectObject (DC,RedPen);
  2164.                     for (Loop = 0;Loop < NoOfListObjects;Loop++)
  2165.                         DrawLineDef (DC,ObjectList [Loop]);
  2166.                 }
  2167.                 
  2168.                 // Clean up.
  2169.                 SelectObject (DC,GetStockObject (BLACK_PEN));
  2170.                 ReleaseDC (hWndMain,DC);
  2171.                 SendMessage (hWndSector,REDRAW_MESSAGE,0,0L);
  2172.             }
  2173.             break;
  2174.         default:
  2175.             return DefWindowProc (hWnd,Message,wParam,lParam);
  2176.     }
  2177.     
  2178.     return 0L;
  2179. }
  2180.  
  2181. // ╔════════════════════════════════════════════════════════════════════════╗
  2182. // ║                        Main Program Code                               ║
  2183. // ║                                                                        ║
  2184. // ║ This controls the main application. Here we take care of the main      ║
  2185. // ║ menu, changing the check buttons and switching between various edit    ║
  2186. // ║ modes. The rest is boilerplate windows app.                            ║
  2187. // ╚════════════════════════════════════════════════════════════════════════╝
  2188.  
  2189. LONG FAR PASCAL WndProc (HWND hWnd, WORD Message, WORD wParam, LONG lParam)
  2190. {
  2191.     switch (Message)
  2192.     {
  2193.         case WM_CREATE:
  2194.             if (GridSnap)
  2195.             {
  2196.                 CheckMenuItem (GetMenu (hWnd),204,MF_CHECKED);
  2197.                 GridSnap = TRUE;
  2198.             }
  2199.             break;
  2200.         
  2201.         case WM_COMMAND:
  2202.             switch (wParam)
  2203.             {
  2204.                 case 100: // File new.
  2205.                     NewWadFile ();
  2206.                     break;
  2207.                     
  2208.                 case 101: // File open dialog.
  2209.                     LoadWadFile ();
  2210.                     break;
  2211.                     
  2212.                 case 102: // File save dialog.
  2213.                     if (Registered)
  2214.                     {
  2215.                         if (strlen (FileName) == 0)
  2216.                             SaveWadFile ();
  2217.                         else
  2218.                             WriteWadFile (FileName);
  2219.                     }
  2220.                     break;
  2221.                     
  2222.                 case 103: // File save as dialog.
  2223.                     if (Registered)
  2224.                         SaveWadFile ();
  2225.                     break;
  2226.                     
  2227.                 case 104: // Exit program.
  2228.                     DestroyWindow (hWnd);
  2229.                     PostQuitMessage (0);
  2230.                     break;
  2231.                     
  2232.                 case 200: // Thing Editor.
  2233.                     if (EditMode != THING_EDIT)
  2234.                     {
  2235.                         CheckMenuItem (GetMenu (hWnd),wParam,MF_CHECKED);
  2236.                         CheckMenuItem (GetMenu (hWnd),201,MF_UNCHECKED);
  2237.                         CheckMenuItem (GetMenu (hWnd),202,MF_UNCHECKED);
  2238.                         CheckMenuItem (GetMenu (hWnd),203,MF_UNCHECKED);
  2239.                         ShowWindow (hWndSector,SW_HIDE);
  2240.                         ShowWindow (hWndLineDef,SW_HIDE);
  2241.                         ShowWindow (hWndSideDef,SW_HIDE);
  2242.                         ShowWindow (hWndThing,SW_SHOW);
  2243.                         InvalidateRect (hWndMain,NULL,TRUE);
  2244.                         EditMode = THING_EDIT;
  2245.                     }
  2246.                     break;
  2247.                     
  2248.                 case 201: // Vertex Editor.
  2249.                     if (EditMode != VERTEX_EDIT)
  2250.                     {
  2251.                         CheckMenuItem (GetMenu (hWnd),wParam,MF_CHECKED);
  2252.                         CheckMenuItem (GetMenu (hWnd),200,MF_UNCHECKED);
  2253.                         CheckMenuItem (GetMenu (hWnd),202,MF_UNCHECKED);
  2254.                         CheckMenuItem (GetMenu (hWnd),203,MF_UNCHECKED);
  2255.                         ShowWindow (hWndThing,SW_HIDE);
  2256.                         ShowWindow (hWndSector,SW_HIDE);
  2257.                         ShowWindow (hWndLineDef,SW_HIDE);
  2258.                         ShowWindow (hWndSideDef,SW_HIDE);
  2259.                         InvalidateRect (hWndMain,NULL,TRUE);
  2260.                         EditMode = VERTEX_EDIT;
  2261.                     }
  2262.                     break;
  2263.                     
  2264.                 case 202: // Linedef Editor.
  2265.                     if (EditMode != LINEDEF_EDIT)
  2266.                     {
  2267.                         CheckMenuItem (GetMenu (hWnd),wParam,MF_CHECKED);
  2268.                         CheckMenuItem (GetMenu (hWnd),200,MF_UNCHECKED);
  2269.                         CheckMenuItem (GetMenu (hWnd),201,MF_UNCHECKED);
  2270.                         CheckMenuItem (GetMenu (hWnd),203,MF_UNCHECKED);
  2271.                         ShowWindow (hWndThing,SW_HIDE);
  2272.                         ShowWindow (hWndSector,SW_HIDE);
  2273.                         ShowWindow (hWndLineDef,SW_HIDE);
  2274.                         ShowWindow (hWndSideDef,SW_HIDE);
  2275.                         InvalidateRect (hWndMain,NULL,TRUE);
  2276.                         EditMode = LINEDEF_EDIT;
  2277.                     }
  2278.                     break;
  2279.                     
  2280.                 case 203: // Sector Editor.
  2281.                     if (EditMode != SECTOR_EDIT)
  2282.                     {
  2283.                         CheckMenuItem (GetMenu (hWnd),wParam,MF_CHECKED);
  2284.                         CheckMenuItem (GetMenu (hWnd),200,MF_UNCHECKED);
  2285.                         CheckMenuItem (GetMenu (hWnd),201,MF_UNCHECKED);
  2286.                         CheckMenuItem (GetMenu (hWnd),202,MF_UNCHECKED);
  2287.                         ShowWindow (hWndThing,SW_HIDE);
  2288.                         ShowWindow (hWndLineDef,SW_HIDE);
  2289.                         ShowWindow (hWndSideDef,SW_HIDE);
  2290.                         ShowWindow (hWndSector,SW_SHOW);
  2291.                         InvalidateRect (hWndMain,NULL,TRUE);
  2292.                         EditMode = SECTOR_EDIT;
  2293.                     }
  2294.                     break;
  2295.                     
  2296.                     case 204: // Gridsnap.
  2297.                         if (!GridSnap)
  2298.                         {
  2299.                             CheckMenuItem (GetMenu (hWnd),wParam,MF_CHECKED);
  2300.                             GridSnap = TRUE;
  2301.                         }
  2302.                         else
  2303.                         {
  2304.                             CheckMenuItem (GetMenu (hWnd),wParam,MF_UNCHECKED);
  2305.                             GridSnap = FALSE;
  2306.                         }
  2307.                         break;
  2308.                         
  2309.                 default:
  2310.                     return DefWindowProc (hWnd,Message,wParam,lParam);
  2311.             }
  2312.         break;
  2313.  
  2314.            case WM_CLOSE:
  2315.             DestroyWindow (hWnd);
  2316.             PostQuitMessage (0);
  2317.                break;
  2318.  
  2319.         case WM_PAINT:
  2320.         {
  2321.             PAINTSTRUCT        PS;
  2322.             HDC                DC;
  2323.             
  2324.             DC = BeginPaint (hWnd,&PS);
  2325.             PaintIt (DC);
  2326.             EndPaint (hWnd,&PS);
  2327.         }
  2328.         break;
  2329.         
  2330.         default:
  2331.             switch (EditMode)
  2332.             {
  2333.                 case THING_EDIT:
  2334.                     return ThingEdit (hWnd,Message,wParam,lParam);
  2335.                     break;
  2336.                 
  2337.                 case VERTEX_EDIT:
  2338.                     return VertexEdit (hWnd,Message,wParam,lParam);
  2339.                     break;
  2340.                 
  2341.                 case SECTOR_EDIT:
  2342.                     return SectorEdit (hWnd,Message,wParam,lParam);
  2343.                     break;
  2344.                 
  2345.                 case LINEDEF_EDIT:
  2346.                     return LineDefEdit (hWnd,Message,wParam,lParam);
  2347.                     break;
  2348.                 
  2349.                 default:
  2350.                     return DefWindowProc (hWnd,Message,wParam,lParam);
  2351.             }
  2352.     }
  2353.     
  2354.     return 0L;
  2355. }
  2356.  
  2357.  
  2358. BOOL FAR PASCAL CheapProc (HWND hWndDlg, WORD Message, WORD wParam, LONG lParam)
  2359. {
  2360.     switch (Message)
  2361.     {
  2362.         case WM_CLOSE:
  2363.              PostMessage (hWndDlg,WM_COMMAND,IDCANCEL,0L);
  2364.              break;
  2365.  
  2366.         case WM_COMMAND:
  2367.             switch (wParam)
  2368.                {
  2369.                 case IDOK:
  2370.                      EndDialog (hWndDlg,TRUE);
  2371.                      break;
  2372.                      
  2373.                 case IDCANCEL:
  2374.                      EndDialog (hWndDlg,FALSE);
  2375.                      break;
  2376.                }
  2377.              break;
  2378.  
  2379.         default:
  2380.             return FALSE;
  2381.     }
  2382.     return TRUE;
  2383. }
  2384.  
  2385.  
  2386. int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
  2387. {
  2388.     MSG           msg;
  2389.     WNDCLASS    wndclass;
  2390.     int            FileHandle;
  2391.     FARPROC        lpfnButtonBarMsgProc;
  2392.     FARPROC        lpfnThingProc;
  2393.     FARPROC        lpfnSectorProc;
  2394.     FARPROC        lpfnLineDefProc;
  2395.     FARPROC        lpfnSideDefProc;
  2396.     char        Text [20];
  2397.     int            Loop;
  2398.  
  2399.     hInst = hInstance;
  2400.     
  2401.     // Create some pens. More efficient this way.
  2402.     YellowPen = CreatePen (PS_SOLID,1,YELLOW_COLOUR);
  2403.     RedPen = CreatePen (PS_SOLID,1,RED_COLOUR);
  2404.     BluePen = CreatePen (PS_SOLID,1,BLUE_COLOUR);
  2405.     RedBrush = CreateSolidBrush (RED_COLOUR);
  2406.     BlueBrush = CreateSolidBrush (BLUE_COLOUR);
  2407.     
  2408.     // Read our configuration information.
  2409.     GetPrivateProfileString (SECTION_NAME,"DoomDirectory","C:\\DOOM",DoomWadPath,sizeof (DoomWadPath),PROFILE_FILE);
  2410.     sprintf (DoomWadName,"%s\\DOOM.WAD",DoomWadPath);
  2411.     GridSnap = GetPrivateProfileInt (SECTION_NAME,"GridSnap",32,PROFILE_FILE);
  2412.     GridSize = GetPrivateProfileInt (SECTION_NAME,"GridSize",32,PROFILE_FILE);
  2413.     
  2414.     // Register the window class.
  2415.     if (!hPrevInstance)
  2416.     {
  2417.         // Register window classes if first instance of application.
  2418.         memset (&wndclass,0x00,sizeof (WNDCLASS));
  2419.         wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNWINDOW | CS_DBLCLKS;
  2420.         wndclass.lpfnWndProc = WndProc;
  2421.         wndclass.cbClsExtra = 0;
  2422.         wndclass.cbWndExtra = 0;
  2423.         wndclass.hInstance = hInst;
  2424.         wndclass.hIcon = LoadIcon (hInst,"MAIN_ICON");
  2425.         wndclass.hCursor = LoadCursor (NULL,IDC_ARROW);
  2426.         wndclass.hbrBackground = BlueBrush;
  2427.         wndclass.lpszMenuName = "MAIN_MENU";
  2428.         wndclass.lpszClassName = MainClassName;
  2429.         RegisterClass (&wndclass);
  2430.     }
  2431.  
  2432.     // Main window.
  2433.     hWndMain = CreateWindow (
  2434.         MainClassName,              /* Window class name           */
  2435.         "GDR Doom Thing Editor",/* Window's title              */
  2436.         WS_CAPTION      |       /* Title and Min/Max           */
  2437.         WS_SYSMENU      |       /* Add system menu box         */
  2438.         WS_MINIMIZEBOX  |       /* Add minimize box            */
  2439.         WS_MAXIMIZEBOX  |       /* Add maximize box            */
  2440.         WS_THICKFRAME   |       /* thick sizeable frame        */
  2441.         WS_CLIPCHILDREN |       /* don't draw in child windows areas */
  2442.         WS_OVERLAPPED,
  2443.         CW_USEDEFAULT, 0,       /* Use default X, Y            */
  2444.         CW_USEDEFAULT, 0,       /* Use default X, Y            */
  2445.         NULL,                   /* Parent window's handle      */
  2446.         NULL,                   /* Default to Class Menu       */
  2447.         hInst,                  /* Instance of window          */
  2448.         NULL);                  /* Create struct for WM_CREATE */
  2449.  
  2450.     if (hWndMain == NULL)
  2451.     {
  2452.         MessageBox (NULL,"Unable to create the main window.",NULL,MB_ICONEXCLAMATION);
  2453.         return -1;
  2454.     }
  2455.  
  2456.     // Read in the DOOM.WAD stuff for wall patches and the like.
  2457.     FileHandle = open (DoomWadName,O_BINARY|O_RDONLY);
  2458.     read (FileHandle,&DoomHeader,sizeof (Header));
  2459.     DoomDirectory = new DirectoryEntry [DoomHeader.NumberOfEntries];
  2460.     lseek (FileHandle,DoomHeader.DirectoryPointer,SEEK_SET);
  2461.     lread (FileHandle,DoomDirectory,sizeof (DirectoryEntry) * DoomHeader.NumberOfEntries);
  2462.     close (FileHandle);
  2463.     
  2464.     // Check for registered version.
  2465.     for (Loop = 0;Loop < DoomHeader.NumberOfEntries;Loop++)
  2466.         if (strncmp (DoomDirectory [Loop].ResourceName,"E2M2",8) == 0)
  2467.             Registered = TRUE;
  2468.  
  2469.     // Cheapskate message.
  2470.     if (!Registered)
  2471.     {
  2472.         FARPROC        MsgProc;
  2473.         
  2474.         MsgProc = MakeProcInstance ((FARPROC) CheapProc,hInst);
  2475.         DialogBox (hInst,(LPSTR) "CHEAP_BUGGERS",hWndMain,MsgProc);
  2476.         FreeProcInstance (MsgProc);
  2477.     }
  2478.     
  2479.     // Create the button bar dialog box.
  2480.     lpfnButtonBarMsgProc = MakeProcInstance ((FARPROC) ButtonBarMsgProc,hInst);
  2481.     hWndButtonBar = CreateDialog (hInst,(LPSTR) "BUTTON_BAR",hWndMain,lpfnButtonBarMsgProc);
  2482.  
  2483.     // Create the thing dialog box.
  2484.     lpfnThingProc = MakeProcInstance ((FARPROC) ThingProc,hInst);
  2485.     hWndThing = CreateDialog (hInst,(LPSTR) "THING_EDITOR",hWndMain,lpfnThingProc);
  2486.  
  2487.     // Create the sector dialog box.
  2488.     lpfnSectorProc = MakeProcInstance ((FARPROC) SectorProc,hInst);
  2489.     hWndSector = CreateDialog (hInst,(LPSTR) "SECTOR_EDITOR",hWndMain,lpfnSectorProc);
  2490.  
  2491.     // Create the linedef dialog box.
  2492.     lpfnLineDefProc = MakeProcInstance ((FARPROC) LineDefProc,hInst);
  2493.     hWndLineDef = CreateDialog (hInst,(LPSTR) "LINEDEF_EDITOR",hWndMain,lpfnLineDefProc);
  2494.  
  2495.     // Create the sidedef dialog box.
  2496.     lpfnSideDefProc = MakeProcInstance ((FARPROC) SideDefProc,hInst);
  2497.     hWndSideDef = CreateDialog (hInst,(LPSTR) "SIDEDEF_EDITOR",hWndMain,lpfnSideDefProc);
  2498.  
  2499.     ShowWindow (hWndMain,SW_SHOWMAXIMIZED);
  2500.  
  2501.     while (GetMessage (&msg,NULL,0,0))
  2502.     {
  2503.         if (!IsDialogMessage (hWndThing,&msg) && !IsDialogMessage (hWndButtonBar,&msg) && !IsDialogMessage (hWndSector,&msg))
  2504.         {
  2505.             TranslateMessage (&msg);
  2506.             DispatchMessage (&msg);
  2507.         }
  2508.     }
  2509.  
  2510.     // Remove our button bar from existence.
  2511.     DestroyWindow (hWndButtonBar);
  2512.     FreeProcInstance (lpfnButtonBarMsgProc);
  2513.  
  2514.     // Remove our thing dialog from existence.
  2515.     DestroyWindow (hWndThing);
  2516.     FreeProcInstance (lpfnThingProc);
  2517.  
  2518.     // Remove our sector dialog from existence.
  2519.     DestroyWindow (hWndSector);
  2520.     FreeProcInstance (lpfnSectorProc);
  2521.  
  2522.     // Remove our linedef dialog from existence.
  2523.     DestroyWindow (hWndLineDef);
  2524.     FreeProcInstance (lpfnLineDefProc);
  2525.  
  2526.     // Remove our linedef dialog from existence.
  2527.     DestroyWindow (hWndSideDef);
  2528.     FreeProcInstance (lpfnSideDefProc);
  2529.  
  2530.     // Delete our pens.
  2531.     DeleteObject (YellowPen);
  2532.     DeleteObject (RedPen);
  2533.     DeleteObject (BluePen);
  2534.     DeleteObject (BlueBrush);
  2535.     DeleteObject (RedBrush);
  2536.     
  2537.     // Write our configuration information.
  2538.     sprintf (Text,"%d",GridSnap);
  2539.     WritePrivateProfileString (SECTION_NAME,"GridSnap",Text,PROFILE_FILE);
  2540.     sprintf (Text,"%d",GridSize);
  2541.     WritePrivateProfileString (SECTION_NAME,"GridSize",Text,PROFILE_FILE);
  2542.     
  2543.     // Clean up before exiting from the application.
  2544.     UnregisterClass (MainClassName,hInst);
  2545.     UnloadWadFile ();
  2546.         
  2547.     return msg.wParam;
  2548. }
  2549.