home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the DOOM Programming Gurus / Tricks_of_the_Doom_Programming_Gurus.iso / bonus / editors / deth / source / levels.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-02  |  32.0 KB  |  998 lines

  1. /*
  2.    Doom Editor Utility, by Brendon Wyber and RaphaĆ«l Quinet.
  3.    
  4.    You are allowed to use any parts of this code in another program, as
  5.    long as you give credits to the authors in the documentation and in
  6.    the program itself.  Read the file README.1ST for more information.
  7.    
  8.    This program comes with absolutely no warranty.
  9.    
  10.    LEVELS.C - Level loading and saving routines.
  11.    */
  12.  
  13. /* the includes */
  14. #include "deu.h"
  15. #include "wstructs.h"
  16.  
  17. /* external function from objects.c */
  18. extern Bool CreateNodes( NPtr*, BCINT *, SEPtr); /* SWAP - needs Vertexes */
  19.  
  20. /* the global data */
  21. MDirPtr Level = NULL;                /* master dictionary entry for the level */
  22. BCINT NumThings = 0;                /* number of things */
  23. TPtr Things;                        /* things data */
  24. BCINT NumLineDefs = 0;                /* number of line defs */
  25. LDPtr LineDefs;                        /* line defs data */
  26. BCINT NumSideDefs = 0;                /* number of side defs */
  27. SDPtr SideDefs;                        /* side defs data */
  28. BCINT NumVertexes = 0;                /* number of vertexes */
  29. VPtr Vertexes;                        /* vertex data */
  30. BCINT NumSectors = 0;                /* number of sectors */
  31. SPtr Sectors;                        /* sectors data */
  32. BCINT NumSegs = 0;                /* number of segments */
  33. SEPtr Segs = NULL;                /* list of segments */
  34. SEPtr LastSeg = NULL;                /* last segment in the list */
  35. BCINT NumSSectors = 0;                /* number of subsectors */
  36. SSPtr SSectors = NULL;                /* list of subsectors */
  37. SSPtr LastSSector = NULL;        /* last subsector in the list */
  38. BCINT NumNodes = 0;                /* number of Nodes */
  39. NPtr Nodes = NULL;                /* nodes tree */
  40. BCINT NumWTexture = 0;                /* number of wall textures */
  41. char **WTexture;                /* array of wall texture names */
  42. char *_WTexture;
  43. BCINT NumFTexture = 0;                /* number of floor/ceiling textures */
  44. char **FTexture;                /* array of texture names */
  45. BCINT MapMaxX = -32767;                /* maximum X value of map */
  46. BCINT MapMaxY = -32767;                /* maximum Y value of map */
  47. BCINT MapMinX = 32767;                /* minimum X value of map */
  48. BCINT MapMinY = 32767;                /* minimum Y value of map */
  49. Bool MadeChanges = FALSE;        /* made changes? */
  50. Bool MadeMapChanges = FALSE;        /* made changes that need rebuilding? */
  51. SelPtr errld = NULL;                /* LineDefs in error (Nodes builder) */
  52.  
  53. SList Texture_sections = NULL;
  54. SList Ftexture_sections = NULL;
  55.  
  56. /*
  57.    read in the level data
  58.    */
  59.  
  60. void ReadLevelData( BCINT episode, BCINT mission) /* SWAP! */
  61. {
  62.     MDirPtr dir;
  63.     char name[ 7];
  64.     BCINT n, m;
  65.     BCINT val;
  66.     BCINT OldNumVertexes;
  67.     BCINT *VertexUsed = -1;
  68.     
  69.     /* No objects are needed: they may be swapped after they have been read */
  70.     ObjectsNeeded( 0);
  71.     
  72.     /* find the various level information from the master directory */
  73.     if(mission != -1)
  74.         sprintf( name, "E%dM%d", episode, mission);
  75.     else
  76.         sprintf( name, "MAP%02d", episode);
  77.     
  78.     DisplayMessage( -1, -1, "Reading data for level %s...", name);
  79.     Level = FindMasterDir( MasterDir, name);
  80.     if (!Level)
  81.         ProgError( "level data not found");
  82.     
  83.     /* get the number of Vertices */
  84.     dir = FindMasterDir( Level, "VERTEXES");
  85.     if (dir != NULL)
  86.         OldNumVertexes = (BCINT) (dir->dir.size / 4L);
  87.     else
  88.         OldNumVertexes = 0;
  89.     if (OldNumVertexes > 0) {
  90.         VertexUsed = (BCINT*)GetMemory( OldNumVertexes * sizeof( BCINT));
  91.         for (n = 0; n < OldNumVertexes; n++)
  92.             VertexUsed[ n] = FALSE;
  93.     }
  94.     
  95.     /* read in the Things data */
  96.     dir = FindMasterDir( Level, "THINGS");
  97.     if (dir != 0)
  98.         NumThings = (BCINT) (dir->dir.size / 10L);
  99.     else
  100.         NumThings = 0;
  101.     if (NumThings > 0) {
  102.         Things = (TPtr)GetFarMemory( (unsigned long) NumThings * sizeof( struct Thing));
  103.         BasicWadSeek( dir->wadfile, dir->dir.start);
  104.         /*    for (n = 0; n < NumThings; n++) {
  105.         BasicWadRead( dir->wadfile, &(Things[ n].xpos), 2);
  106.         BasicWadRead( dir->wadfile, &(Things[ n].ypos), 2);
  107.         BasicWadRead( dir->wadfile, &(Things[ n].angle), 2);
  108.         BasicWadRead( dir->wadfile, &(Things[ n].type), 2);
  109.         BasicWadRead( dir->wadfile, &(Things[ n].when), 2);
  110.         } */
  111.         BasicWadRead(dir->wadfile, Things, 10 * NumThings);
  112.     }
  113.     
  114.     /* read in the LineDef information */
  115.     dir = FindMasterDir( Level, "LINEDEFS");
  116.     if (dir != NULL)
  117.         NumLineDefs = (BCINT) (dir->dir.size / 14L);
  118.     else
  119.         NumLineDefs = 0;
  120.     if (NumLineDefs > 0) {
  121.         LineDefs = (LDPtr)GetFarMemory( (unsigned long) NumLineDefs * sizeof( struct LineDef));
  122.         BasicWadSeek( dir->wadfile, dir->dir.start);
  123.         for (n = 0; n < NumLineDefs; n++) {
  124.             BasicWadRead( dir->wadfile, &(LineDefs[ n].start), 2);
  125.             VertexUsed[ LineDefs[ n].start] = TRUE;
  126.             BasicWadRead( dir->wadfile, &(LineDefs[ n].end), 2);
  127.             VertexUsed[ LineDefs[ n].end] = TRUE;
  128.             BasicWadRead( dir->wadfile, &(LineDefs[ n].flags), 2);
  129.             BasicWadRead( dir->wadfile, &(LineDefs[ n].type), 2);
  130.             BasicWadRead( dir->wadfile, &(LineDefs[ n].tag), 2);
  131.             BasicWadRead( dir->wadfile, &(LineDefs[ n].sidedef1), 2);
  132.             BasicWadRead( dir->wadfile, &(LineDefs[ n].sidedef2), 2);
  133.         }
  134.     }
  135.     
  136.     /* read in the SideDef information */
  137.     dir = FindMasterDir( Level, "SIDEDEFS");
  138.     if (dir != NULL)
  139.         NumSideDefs = (BCINT) (dir->dir.size / 30L);
  140.     else
  141.         NumSideDefs = 0;
  142.     if (NumSideDefs > 0) {
  143.         SideDefs = (SDPtr)GetFarMemory( (unsigned long) NumSideDefs * sizeof( struct SideDef));
  144.         BasicWadSeek( dir->wadfile, dir->dir.start);
  145.         for (n = 0; n < NumSideDefs; n++) {
  146.             BasicWadRead( dir->wadfile, &(SideDefs[ n].xoff), 2);
  147.             BasicWadRead( dir->wadfile, &(SideDefs[ n].yoff), 2);
  148.             BasicWadRead( dir->wadfile, &(SideDefs[ n].tex1), 8);
  149.             BasicWadRead( dir->wadfile, &(SideDefs[ n].tex2), 8);
  150.             BasicWadRead( dir->wadfile, &(SideDefs[ n].tex3), 8);
  151.             BasicWadRead( dir->wadfile, &(SideDefs[ n].sector), 2);
  152.         }
  153.     }
  154.     
  155.     /* read in the Vertices which are all the corners of the level, but ignore the */
  156.     /* Vertices not used in any LineDef (they usually are at the end of the list). */
  157.     NumVertexes = 0;
  158.     for (n = 0; n < OldNumVertexes; n++)
  159.         if (VertexUsed[ n])
  160.             NumVertexes++;
  161.     if (NumVertexes > 0) {
  162.         Vertexes = (VPtr)GetFarMemory( (unsigned long) NumVertexes * sizeof( struct Vertex));
  163.         dir = FindMasterDir( Level, "VERTEXES");
  164.         BasicWadSeek( dir->wadfile, dir->dir.start);
  165.         MapMaxX = -32767;
  166.         MapMaxY = -32767;
  167.         MapMinX = 32767;
  168.         MapMinY = 32767;
  169.         m = 0;
  170.         for (n = 0; n < OldNumVertexes; n++) {
  171.             BasicWadRead( dir->wadfile, &val, 2);
  172.             if (VertexUsed[ n]) {
  173.                 if (val < MapMinX)
  174.                     MapMinX = val;
  175.                 if (val > MapMaxX)
  176.                     MapMaxX = val;
  177.                 Vertexes[ m].x = val;
  178.             }
  179.             BasicWadRead( dir->wadfile, &val, 2);
  180.             if (VertexUsed[ n]) {
  181.                 if (val < MapMinY)
  182.                     MapMinY = val;
  183.                 if (val > MapMaxY)
  184.                     MapMaxY = val;
  185.                 Vertexes[ m].y = val;
  186.                 m++;
  187.             }
  188.         }
  189.         if (m != NumVertexes)
  190.             ProgError("inconsistency in the Vertexes data\n");
  191.     }
  192.     
  193.     if (OldNumVertexes > 0) {
  194.         /* update the Vertex numbers in the LineDefs (not really necessary, but...) */
  195.         m = 0;
  196.         for (n = 0; n < OldNumVertexes; n++)
  197.             if (VertexUsed[ n])
  198.                 VertexUsed[ n] = m++;
  199.         ObjectsNeeded( OBJ_LINEDEFS, 0);
  200.         for (n = 0; n < NumLineDefs; n++) {
  201.             LineDefs[ n].start = VertexUsed[ LineDefs[ n].start];
  202.             LineDefs[ n].end = VertexUsed[ LineDefs[ n].end];
  203.         }
  204.         ObjectsNeeded( 0);
  205.         FreeMemory( VertexUsed);
  206.     }
  207.     
  208.     /* ignore the Segs, SSectors and Nodes */
  209.     
  210.     /* read in the Sectors information */
  211.     dir = FindMasterDir( Level, "SECTORS");
  212.     if (dir != NULL)
  213.         NumSectors = (BCINT) (dir->dir.size / 26L);
  214.     else
  215.         NumSectors = 0;
  216.     if (NumSectors > 0) {
  217.         Sectors = (SPtr)GetFarMemory( (unsigned long) NumSectors * sizeof( struct Sector));
  218.         BasicWadSeek( dir->wadfile, dir->dir.start);
  219.         for (n = 0; n < NumSectors; n++) {
  220.             BasicWadRead( dir->wadfile, &(Sectors[ n].floorh), 2);
  221.             BasicWadRead( dir->wadfile, &(Sectors[ n].ceilh), 2);
  222.             BasicWadRead( dir->wadfile, &(Sectors[ n].floort), 8);
  223.             BasicWadRead( dir->wadfile, &(Sectors[ n].ceilt), 8);
  224.             BasicWadRead( dir->wadfile, &(Sectors[ n].light), 2);
  225.             BasicWadRead( dir->wadfile, &(Sectors[ n].special), 2);
  226.             BasicWadRead( dir->wadfile, &(Sectors[ n].tag), 2);
  227.         }
  228.     }
  229.     
  230.     /* ignore the last entries (Reject & BlockMap) */
  231. }
  232.  
  233.  
  234.  
  235. /*
  236.    forget the level data
  237.    */
  238.  
  239. void ForgetLevelData() /* SWAP! */
  240. {
  241.     /* forget the Things */
  242.     ObjectsNeeded( OBJ_THINGS, 0);
  243.     NumThings = 0;
  244.     if (Things)
  245.         FreeFarMemory( Things);
  246.     Things = NULL;
  247.     
  248.     /* forget the Vertices */
  249.     ObjectsNeeded( OBJ_VERTEXES, 0);
  250.     NumVertexes = 0;
  251.     if (Vertexes)
  252.         FreeFarMemory( Vertexes);
  253.     Vertexes = NULL;
  254.     
  255.     /* forget the LineDefs */
  256.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  257.     NumLineDefs = 0;
  258.     if (LineDefs)
  259.         FreeFarMemory( LineDefs);
  260.     LineDefs = NULL;
  261.     
  262.     /* forget the SideDefs */
  263.     ObjectsNeeded( OBJ_SIDEDEFS, 0);
  264.     NumSideDefs = 0;
  265.     if (SideDefs)
  266.         FreeFarMemory( SideDefs);
  267.     SideDefs = NULL;
  268.     
  269.     /* forget the Sectors */
  270.     ObjectsNeeded( OBJ_SECTORS, 0);
  271.     NumSectors = 0;
  272.     if (Sectors)
  273.         FreeFarMemory( Sectors);
  274.     Sectors = NULL;
  275.     ObjectsNeeded( 0);
  276. }
  277.  
  278.  
  279.  
  280. /*
  281.    recursively save the Nodes data to a PWAD file
  282.    */
  283.  
  284. void SaveNodes( FILE *file, NPtr node)
  285. {
  286.     /* Nodes tree walk: save child1, save child2, save parent */
  287.     if ((node->child1 & 0x8000) == 0) {
  288.         SaveNodes( file, node->node1);
  289.         node->child1 = node->node1->num;
  290.     }
  291.     if ((node->child2 & 0x8000) == 0) {
  292.         SaveNodes( file, node->node2);
  293.         node->child2 = node->node2->num;
  294.     }
  295.     WriteBytes( file, &(node->x), 2L);
  296.     WriteBytes( file, &(node->y), 2L);
  297.     WriteBytes( file, &(node->dx), 2L);
  298.     WriteBytes( file, &(node->dy), 2L);
  299.     WriteBytes( file, &(node->maxy1), 2L);
  300.     WriteBytes( file, &(node->miny1), 2L);
  301.     WriteBytes( file, &(node->minx1), 2L);
  302.     WriteBytes( file, &(node->maxx1), 2L);
  303.     WriteBytes( file, &(node->maxy2), 2L);
  304.     WriteBytes( file, &(node->miny2), 2L);
  305.     WriteBytes( file, &(node->minx2), 2L);
  306.     WriteBytes( file, &(node->maxx2), 2L);
  307.     WriteBytes( file, &(node->child1), 2L);
  308.     WriteBytes( file, &(node->child2), 2L);
  309.     node->num = NumNodes++;
  310. }
  311.  
  312.  
  313.  
  314. /*
  315.    forget the Nodes
  316.    */
  317.  
  318. void ForgetNodes( NPtr node)
  319. {
  320.     if ((node->child1 & 0x8000) == 0)
  321.         ForgetNodes( node->node1);
  322.     if ((node->child2 & 0x8000) == 0)
  323.         ForgetNodes( node->node2);
  324.     FreeFarMemory( node);
  325. }
  326.  
  327.  
  328.  
  329. /*
  330.    save the level data to a PWAD file
  331.    */
  332.  
  333. void SaveLevelData( char *outfile) /* SWAP! */
  334. {
  335.     FILE   *file;
  336.     MDirPtr dir;
  337.     long    counter = 11;
  338.     BCINT   n, i, j;
  339.     void   *data;
  340.     long    size;
  341.     long    dirstart;
  342.     BCINT   *blockptr;
  343.     long    blocksize;
  344.     BCINT   blockcount;
  345.     long    oldpos;
  346.     Bool    newnodes;
  347.     long    rejectsize;
  348.     BCINT   oldNumVertexes;
  349.     Bool usem = UseMouse;
  350.     
  351.     UseMouse = FALSE;
  352.     if (usem)
  353.         HideMousePointer();
  354.     
  355.     DisplayMessage( -1, -1, "Saving data to \"%s\"...", outfile);
  356.     LogMessage( ": Saving data to \"%s\"...\n", outfile);
  357.     oldNumVertexes = NumVertexes;
  358.     /* open the file */
  359.     if ((file = fopen( outfile, "wb")) == NULL)
  360.         ProgError( "Unable to open file \"%s\"", outfile);
  361.     WriteBytes( file, "PWAD", 4L);     /* PWAD file */
  362.     WriteBytes( file, &counter, 4L);   /* 11 entries */
  363.     WriteBytes( file, &counter, 4L);   /* fix this up later */
  364.     counter = 12L;
  365.     dir = Level->next;
  366.     
  367.     /* output the things data */
  368.     ObjectsNeeded( OBJ_THINGS, 0);
  369.     for (n = 0; n < NumThings; n++) {
  370.         WriteBytes( file, &(Things[ n].xpos), 2L);
  371.         WriteBytes( file, &(Things[ n].ypos), 2L);
  372.         WriteBytes( file, &(Things[ n].angle), 2L);
  373.         WriteBytes( file, &(Things[ n].type), 2L);
  374.         WriteBytes( file, &(Things[ n].when), 2L);
  375.         counter += 10L;
  376.     }
  377.     dir = dir->next;
  378.     
  379.     /* update MapMinX, MapMinY, MapMaxX, MapMaxY */
  380.     ObjectsNeeded( OBJ_VERTEXES, 0);
  381.     MapMaxX = -32767;
  382.     MapMaxY = -32767;
  383.     MapMinX = 32767;
  384.     MapMinY = 32767;
  385.     for (n = 0; n < NumVertexes; n++) {
  386.         if (Vertexes[ n].x < MapMinX)
  387.             MapMinX = Vertexes[ n].x;
  388.         if (Vertexes[ n].x > MapMaxX)
  389.             MapMaxX = Vertexes[ n].x;
  390.         if (Vertexes[ n].y < MapMinY)
  391.             MapMinY = Vertexes[ n].y;
  392.         if (Vertexes[ n].y > MapMaxY)
  393.             MapMaxY = Vertexes[ n].y;
  394.     }
  395.     
  396.     /* do we need to rebuild the Nodes, Segs and SSectors? */
  397.     if (MadeMapChanges && (Expert || Confirm( -1, 270, "Do you want to rebuild the NODES, SEGS, SSECTORS, REJECT and BLOCKMAP?",
  398.                                              "WARNING: You won't be able to use your level if you don't do this..."))) {
  399.         SEPtr seglist;
  400.         
  401.         if (UseMouse)
  402.             HideMousePointer();
  403.         ClearScreen();
  404.         DrawScreenBox3D( 218, 0, ScrMaxX, 55);
  405.         SetColor( WHITE);
  406.         DrawScreenText( 225, 10, "Rebuilding the NODES...");
  407.         DrawScreenBoxHollow( 225, 28, ScrMaxX - 10, 48);
  408.         DrawScreenMeter( 225, 28, ScrMaxX - 10, 48, 0.0);
  409.         if (UseMouse)
  410.             ShowMousePointer();
  411.         seglist = NULL;
  412.         ObjectsNeeded( OBJ_LINEDEFS, OBJ_VERTEXES, 0);
  413.         for (n = 0; n < NumLineDefs; n++) {
  414.             if (LineDefs[ n].sidedef1 >= 0) {
  415.                 if (seglist) {
  416.                     LastSeg->next = (SEPtr) GetMemory( sizeof( struct Seg));
  417.                     LastSeg = LastSeg->next;
  418.                 }
  419.                 else {
  420.                     seglist = (SEPtr) GetMemory( sizeof( struct Seg));
  421.                     LastSeg = seglist;
  422.                 }
  423.                 LastSeg->next = NULL;
  424.                 LastSeg->start = LineDefs[ n].start;
  425.                 LastSeg->end = LineDefs[ n].end;
  426.                 LastSeg->angle = ComputeAngle(Vertexes[ LineDefs[ n].end].x - Vertexes[ LineDefs[ n].start].x,
  427.                                               Vertexes[ LineDefs[ n].end].y - Vertexes[ LineDefs[ n].start].y);
  428.                 LastSeg->linedef = n;
  429.                 LastSeg->flip = 0;
  430.                 LastSeg->dist = 0;
  431.             }
  432.             if (LineDefs[ n].sidedef2 >= 0) {
  433.                 if (seglist) {
  434.                     LastSeg->next = (SEPtr) GetMemory( sizeof( struct Seg));
  435.                     LastSeg = LastSeg->next;
  436.                 }
  437.                 else {
  438.                     seglist = (SEPtr) GetMemory( sizeof( struct Seg));
  439.                     LastSeg = seglist;
  440.                 }
  441.                 LastSeg->next = NULL;
  442.                 LastSeg->start = LineDefs[ n].end;
  443.                 LastSeg->end = LineDefs[ n].start;
  444.                 LastSeg->angle = ComputeAngle(Vertexes[ LineDefs[ n].start].x - Vertexes[ LineDefs[ n].end].x,
  445.                                               Vertexes[ LineDefs[ n].start].y - Vertexes[ LineDefs[ n].end].y);
  446.                 LastSeg->linedef = n;
  447.                 LastSeg->flip = 1;
  448.                 LastSeg->dist = 0;
  449.             }
  450.         }
  451.         ShowProgress( OBJ_VERTEXES);
  452.         ShowProgress( OBJ_SIDEDEFS);
  453.         LogMessage( ": Starting Nodes builder...\n");
  454.         LogMessage( "\tNumber of Vertices: %d\n", NumVertexes);
  455.         LogMessage( "\tNumber of Segs:     %d\n", NumSegs);
  456.         ObjectsNeeded( OBJ_VERTEXES, 0);
  457.         if (CreateNodes( &Nodes, &n, seglist) == FALSE) {
  458.             Beep();
  459.             Beep();
  460.             Beep();
  461.             LogMessage( "\nError: CreateNodes failed!\n\n");
  462.             Beep();
  463.             Beep();
  464.             Beep();
  465.         }  
  466.         LogMessage( ": Nodes created OK.\n");
  467.         LogMessage( "\tNumber of Vertices: %d\n", NumVertexes);
  468.         LogMessage( "\tNumber of SideDefs: %d\n", NumSideDefs);
  469.         LogMessage( "\tNumber of Segs:     %d\n", NumSegs);
  470.         LogMessage( "\tNumber of SSectors: %d\n", NumSSectors);
  471.         if (UseMouse)
  472.             HideMousePointer();
  473.         DrawScreenMeter( 225, 28, ScrMaxX - 10, 48, 1.0);
  474.         if (UseMouse)
  475.             ShowMousePointer();
  476.         newnodes = TRUE;
  477.     }
  478.     else
  479.         newnodes = FALSE;
  480.     
  481.     /* output the LineDefs */
  482.     ObjectsNeeded( OBJ_LINEDEFS, 0);
  483.     for (n = 0; n < NumLineDefs; n++) {
  484.         WriteBytes( file, &(LineDefs[ n].start), 2L);
  485.         WriteBytes( file, &(LineDefs[ n].end), 2L);
  486.         WriteBytes( file, &(LineDefs[ n].flags), 2L);
  487.         WriteBytes( file, &(LineDefs[ n].type), 2L);
  488.         WriteBytes( file, &(LineDefs[ n].tag), 2L);
  489.         WriteBytes( file, &(LineDefs[ n].sidedef1), 2L);
  490.         WriteBytes( file, &(LineDefs[ n].sidedef2), 2L);
  491.         counter += 14L;
  492.     }
  493.     dir = dir->next;
  494.     
  495.     /* output the SideDefs */
  496.     ObjectsNeeded( OBJ_SIDEDEFS, 0);
  497.     for (n = 0; n < NumSideDefs; n++) {
  498.         WriteBytes( file, &(SideDefs[ n].xoff), 2L);
  499.         WriteBytes( file, &(SideDefs[ n].yoff), 2L);
  500.         WriteBytes( file, &(SideDefs[ n].tex1), 8L);
  501.         WriteBytes( file, &(SideDefs[ n].tex2), 8L);
  502.         WriteBytes( file, &(SideDefs[ n].tex3), 8L);
  503.         WriteBytes( file, &(SideDefs[ n].sector), 2L);
  504.         counter += 30L;
  505.     }
  506.     dir = dir->next;
  507.     
  508.     if (MadeMapChanges) {
  509.         /* output the Vertices */
  510.         ObjectsNeeded( OBJ_VERTEXES, 0);
  511.         for (n = 0; n < NumVertexes; n++) {
  512.             WriteBytes( file, &(Vertexes[ n].x), 2L);
  513.             WriteBytes( file, &(Vertexes[ n].y), 2L);
  514.             counter += 4L;
  515.         }
  516.     }
  517.     else {
  518.         /* copy the Vertices */
  519.         ObjectsNeeded( 0);
  520.         size = dir->dir.size;
  521.         counter += size;
  522.         BasicWadSeek( dir->wadfile, dir->dir.start);
  523.         CopyBytes( file, dir->wadfile->fileinfo, size);
  524.     }
  525.     dir = dir->next;
  526.     
  527.     if (newnodes) {
  528.         SEPtr curse, oldse;
  529.         SSPtr curss, oldss;
  530.         
  531.         ObjectsNeeded( 0);
  532.         /* output and forget the Segments */
  533.         curse = Segs;
  534.         while (curse) {
  535.             WriteBytes( file, &(curse->start), 2L);
  536.             WriteBytes( file, &(curse->end), 2L);
  537.             WriteBytes( file, &(curse->angle), 2L);
  538.             WriteBytes( file, &(curse->linedef), 2L);
  539.             WriteBytes( file, &(curse->flip), 2L);
  540.             WriteBytes( file, &(curse->dist), 2L);
  541.             oldse = curse;
  542.             curse = curse->next;
  543.             FreeFarMemory( oldse);
  544.             counter += 12L;
  545.         }
  546.         Segs = NULL;
  547.         dir = dir->next;
  548.         
  549.         /* output and forget the SSectors */
  550.         curss = SSectors;
  551.         while (curss) {
  552.             WriteBytes( file, &(curss->num), 2L);
  553.             WriteBytes( file, &(curss->first), 2L);
  554.             oldss = curss;
  555.             curss = curss->next;
  556.             FreeFarMemory( oldss);
  557.             counter += 4L;
  558.         }
  559.         SSectors = NULL;
  560.         dir = dir->next;
  561.         
  562.         /* output the Nodes */
  563.         NumNodes = 0;
  564.         SaveNodes( file, Nodes);
  565.         counter += (long) NumNodes * 28L;
  566.         dir = dir->next;
  567.         
  568.         /* forget the Nodes */
  569.         ForgetNodes( Nodes);
  570.         Nodes = NULL;
  571.     }
  572.     else {
  573.         /* copy the Segs, SSectors and Nodes */
  574.         for (n = 0; n < 3; n++) {
  575.             size = dir->dir.size;
  576.             counter += size;
  577.             BasicWadSeek( dir->wadfile, dir->dir.start);
  578.             CopyBytes( file, dir->wadfile->fileinfo, size);
  579.             dir = dir->next;
  580.         }
  581.     }
  582.     
  583.     /* output the Sectors */
  584.     ObjectsNeeded( OBJ_SECTORS, 0);
  585.     for (n = 0; n < NumSectors; n++) {
  586.         WriteBytes( file, &(Sectors[ n].floorh), 2L);
  587.         WriteBytes( file, &(Sectors[ n].ceilh), 2L);
  588.         WriteBytes( file, &(Sectors[ n].floort), 8L);
  589.         WriteBytes( file, &(Sectors[ n].ceilt), 8L);
  590.         WriteBytes( file, &(Sectors[ n].light), 2L);
  591.         WriteBytes( file, &(Sectors[ n].special), 2L);
  592.         WriteBytes( file, &(Sectors[ n].tag), 2L);
  593.         counter += 26L;
  594.     }
  595.     dir = dir->next;
  596.     
  597.     if (newnodes) {
  598.         /* create and output the reject data */
  599.         ObjectsNeeded( OBJ_SECTORS, 0); /* !!! */
  600.         if (UseMouse)
  601.             HideMousePointer();
  602.         DrawScreenBox3D( 218, 80, ScrMaxX, 135);
  603.         SetColor( WHITE);
  604.         DrawScreenText( 225, 90, "Rebuilding the REJECT data...");
  605.         DrawScreenBoxHollow( 225, 108, ScrMaxX - 10, 128);
  606.         DrawScreenMeter( 225, 108, ScrMaxX - 10, 128, 0.0);
  607.         if (UseMouse)
  608.             ShowMousePointer();
  609.         rejectsize = ((long) NumSectors * (long) NumSectors + 7L) / 8L;
  610.         data = GetMemory( (size_t) rejectsize);
  611.         for (i = 0; i < rejectsize; i++)
  612.             ((char *) data)[ i] = 0;
  613.         for (i = 0; i < NumSectors; i++) {
  614.             if (UseMouse)
  615.                 HideMousePointer();
  616.             DrawScreenMeter( 225, 108, ScrMaxX - 10, 128, (float) i / (float) NumSectors);
  617.             if (UseMouse)
  618.                 ShowMousePointer();
  619.             for (j = 0; j < NumSectors; j++) {
  620.                 /*
  621.                    if (Reject( i, j))
  622.                    data[ (i * NumSectors + j) / 8] |= 1 <<
  623.                    */
  624.             }
  625.         }
  626.         if (UseMouse)
  627.             HideMousePointer();
  628.         DrawScreenMeter( 225, 108, ScrMaxX - 10, 128, 1.0);
  629.         if (UseMouse)
  630.             ShowMousePointer();
  631.         WriteBytes( file, data, rejectsize);
  632.         counter += rejectsize;
  633.         dir = dir->next;
  634.         FreeMemory( data);
  635.     }
  636.     else {
  637.         /* copy the Reject data */
  638.         ObjectsNeeded( 0);
  639.         rejectsize = dir->dir.size;
  640.         size = rejectsize;
  641.         counter += size;
  642.         BasicWadSeek( dir->wadfile, dir->dir.start);
  643.         CopyBytes( file, dir->wadfile->fileinfo, size);
  644.         dir = dir->next;
  645.     }
  646.     
  647.     if (newnodes) {
  648.         /* create and output the blockmap */
  649.         
  650.         BCINT mminx, mminy, mnumx, mnumy;
  651.         
  652.         ObjectsNeeded( OBJ_LINEDEFS, OBJ_VERTEXES, 0);
  653.         if (UseMouse)
  654.             HideMousePointer();
  655.         DrawScreenBox3D( 218, 160, ScrMaxX, 215);
  656.         SetColor( WHITE);
  657.         DrawScreenText( 225, 170, "Rebuilding the BLOCKMAP...");
  658.         DrawScreenBoxHollow( 225, 188, ScrMaxX - 10, 208);
  659.         DrawScreenMeter( 225, 188, ScrMaxX - 10, 208, 0.0);
  660.         if (UseMouse)
  661.             ShowMousePointer();
  662.         mminx = (BCINT) (MapMinX / 8 - 8) * 8;
  663.         WriteBytes( file, &mminx, 2L);
  664.         mminy = (BCINT) (MapMinY / 8 - 8) * 8;
  665.         WriteBytes( file, &mminy, 2L);
  666.         mnumx = MapMaxX / 128 - MapMinX / 128 + 2;
  667.         WriteBytes( file, &mnumx, 2L);
  668.         mnumy = MapMaxY / 128 - MapMinY / 128 + 2;
  669.         WriteBytes( file, &mnumy, 2L);
  670.         counter += 8L;
  671.         oldpos = ftell( file);
  672.         blocksize = (long) (mnumx * mnumy * sizeof( BCINT));
  673.         blockptr = (BCINT*) GetMemory( blocksize);
  674.         WriteBytes( file, blockptr, blocksize);
  675.         blocksize += 8L;
  676.         counter += blocksize - 7L;
  677.         blockcount = mnumx * mnumy + 4;
  678.         for (i = 0; i < mnumy; i++) {
  679.             if (UseMouse)
  680.                 HideMousePointer();
  681.             DrawScreenMeter( 225, 188, ScrMaxX - 10, 208, (float) i / (float) mnumy);
  682.             if (UseMouse)
  683.                 ShowMousePointer();
  684.             for (j = 0; j < mnumx; j++) {
  685.                 blockptr[ mnumx * i + j] = blockcount;
  686.                 n = 0;
  687.                 WriteBytes( file, &n, 2L);
  688.                 counter += 2L;
  689.                 blocksize += 2L;
  690.                 blockcount++;
  691.                 for (n = 0; n < NumLineDefs; n++)
  692.                     if (IsLineDefInside( n, mminx + j * 128, mminy + i * 128, mminx + 127 + j * 128, mminy + 127 + i * 128)) {
  693.                         WriteBytes( file, &n, 2L);
  694.                         counter += 2L;
  695.                         blocksize += 2L;
  696.                         blockcount++;
  697.                     }
  698.                 n = -1;
  699.                 WriteBytes( file, &n, 2L);
  700.                 counter += 2L;
  701.                 blocksize += 2L;
  702.                 blockcount++;
  703.             }
  704.         }
  705.         if (UseMouse)
  706.             HideMousePointer();
  707.         DrawScreenMeter( 225, 188, ScrMaxX - 10, 208, 1.0);
  708.         if (UseMouse)
  709.             ShowMousePointer();
  710.         size = ftell( file);
  711.         fseek( file, oldpos, SEEK_SET);
  712.         WriteBytes( file, blockptr, (long) (mnumx * mnumy * sizeof( BCINT)));
  713.         fseek( file, size, SEEK_SET);
  714.         if (FindMasterDir( dir, "P2_END"))
  715.             counter--;
  716.         FreeMemory( blockptr);
  717.     }
  718.     else {
  719.         /* copy the blockmap data */
  720.         ObjectsNeeded( 0);
  721.         blocksize = dir->dir.size;
  722.         size = blocksize;
  723.         counter += size;
  724.         BasicWadSeek( dir->wadfile, dir->dir.start);
  725.         CopyBytes( file, dir->wadfile->fileinfo, size);
  726.         dir = dir->next;
  727.     }
  728.     
  729.     
  730.     /* output the actual directory */
  731.     dirstart = counter;
  732.     counter = 12L;
  733.     size = 0L;
  734.     dir = Level;
  735.     WriteBytes( file, &counter, 4L);
  736.     WriteBytes( file, &size, 4L);
  737.     WriteBytes( file, &(dir->dir.name), 8L);
  738.     dir = dir->next;
  739.     
  740.     size = (long) NumThings * 10L;
  741.     WriteBytes( file, &counter, 4L);
  742.     WriteBytes( file, &size, 4L);
  743.     WriteBytes( file, "THINGS\0\0", 8L);
  744.     counter += size;
  745.     dir = dir->next;
  746.     
  747.     size = (long) NumLineDefs * 14L;
  748.     WriteBytes( file, &counter, 4L);
  749.     WriteBytes( file, &size, 4L);
  750.     WriteBytes( file, "LINEDEFS", 8L);
  751.     counter += size;
  752.     dir = dir->next;
  753.     
  754.     size = (long) NumSideDefs * 30L;
  755.     WriteBytes( file, &counter, 4L);
  756.     WriteBytes( file, &size, 4L);
  757.     WriteBytes( file, "SIDEDEFS", 8L);
  758.     counter += size;
  759.     dir = dir->next;
  760.     
  761.     if (MadeMapChanges)
  762.         size = (long) NumVertexes * 4L;
  763.     else
  764.         size = dir->dir.size;
  765.     WriteBytes( file, &counter, 4L);
  766.     WriteBytes( file, &size, 4L);
  767.     WriteBytes( file, "VERTEXES", 8L);
  768.     counter += size;
  769.     dir = dir->next;
  770.     
  771.     if (newnodes)
  772.         size = (long) NumSegs * 12L;
  773.     else
  774.         size = dir->dir.size;
  775.     WriteBytes( file, &counter, 4L);
  776.     WriteBytes( file, &size, 4L);
  777.     WriteBytes( file, "SEGS\0\0\0\0", 8L);
  778.     counter += size;
  779.     dir = dir->next;
  780.     
  781.     if (newnodes)
  782.         size = (long) NumSSectors * 4L;
  783.     else
  784.         size = dir->dir.size;
  785.     WriteBytes( file, &counter, 4L);
  786.     WriteBytes( file, &size, 4L);
  787.     WriteBytes( file, "SSECTORS", 8L);
  788.     counter += size;
  789.     dir = dir->next;
  790.     
  791.     if (newnodes)
  792.         size = (long) NumNodes * 28L;
  793.     else
  794.         size = dir->dir.size;
  795.     WriteBytes( file, &counter, 4L);
  796.     WriteBytes( file, &size, 4L);
  797.     WriteBytes( file, "NODES\0\0\0", 8L);
  798.     counter += size;
  799.     dir = dir->next;
  800.     
  801.     size = (long) NumSectors * 26L;
  802.     WriteBytes( file, &counter, 4L);
  803.     WriteBytes( file, &size, 4L);
  804.     WriteBytes( file, "SECTORS\0", 8L);
  805.     counter += size;
  806.     dir = dir->next;
  807.     
  808.     size = rejectsize;
  809.     WriteBytes( file, &counter, 4L);
  810.     WriteBytes( file, &size, 4L);
  811.     WriteBytes( file, "REJECT\0\0", 8L);
  812.     counter += size;
  813.     dir = dir->next;
  814.     
  815.     size = blocksize;
  816.     WriteBytes( file, &counter, 4L);
  817.     WriteBytes( file, &size, 4L);
  818.     WriteBytes( file, "BLOCKMAP", 8L);
  819.     counter += size;
  820.     dir = dir->next;
  821.     
  822.     /* fix up the directory start information */
  823.     if (fseek( file, 8L, SEEK_SET))
  824.         ProgError( "error writing to file");
  825.     WriteBytes( file, &dirstart, 4L);
  826.     
  827.     /* close the file */
  828.     fclose( file);
  829.     
  830.     NumSegs = 0;
  831.     NumSSectors = 0;
  832.     NumNodes = 0;
  833.     
  834.     /* delete the vertices added by the Nodes builder */
  835.     if (NumVertexes != oldNumVertexes) {
  836.         ObjectsNeeded( OBJ_VERTEXES, 0);
  837.         NumVertexes = oldNumVertexes;
  838.         ResizeFarMemory( Vertexes, NumVertexes * sizeof( struct Vertex));
  839.     }
  840.     
  841.     /* the file is now up to date */
  842.     MadeChanges = FALSE;
  843.     if (newnodes)
  844.         MadeMapChanges = FALSE;
  845.     ObjectsNeeded( 0);
  846.     
  847.     /* update pointers in Master Directory */
  848.     OpenPatchWad( outfile);
  849.     
  850.     /* this should free the old "*.BAK" file */
  851.     CloseUnusedWadFiles();
  852.     
  853.     UseMouse = usem;
  854.     if (UseMouse)
  855.         ShowMousePointer();
  856. }
  857.  
  858.  
  859.  
  860. /*
  861.    function used by qsort to sort the texture names
  862.    */
  863. int SortTextures( const void *a, const void *b)
  864. {
  865.     return strcmp( *((char **)a), *((char **)b));
  866. }
  867.  
  868.  
  869.  
  870. /*
  871.    read in the wall texture names
  872.    */
  873.  
  874. void ReadWTextureNames()
  875. {
  876.     BCINT i, j;
  877.     void *resource;
  878.     long nTexture = 0, n;
  879.     Texture *p;
  880.     SList l;
  881.  
  882.     printf("Reading wall texture names\n");
  883.  
  884.     for(l = Texture_sections; l; l = l->next) {
  885.         resource = GetResource(l->string);
  886.         n = *((long *)resource);
  887.         nTexture += n;
  888.     }
  889.  
  890.     NumWTexture = nTexture + 1;
  891.     /* + 1 to allow for the `-' texture */
  892.  
  893.     WTexture = (char **)GetMemory(sizeof(char *) * NumWTexture);
  894.     _WTexture = (char *)GetMemory(9 * sizeof(char) * NumWTexture);
  895.  
  896.     WTexture[0] = _WTexture;
  897.     strcpy(WTexture[0], "-");
  898.  
  899.     j = 1;
  900.     for(l = Texture_sections; l; l = l->next) {
  901.         resource = GetResource(l->string);
  902.         n = *((long *)resource);
  903.         for(i = 1; i <= n; i++, j++) {
  904.             WTexture[j] = _WTexture + 9 * j;
  905.             p = (Texture *)(((long *)resource)[i]);
  906.             p = (Texture *)((long)p + (long)resource);
  907.             strncpy(WTexture[j], p->name, 8);
  908.             WTexture[j][8] = '\0';
  909.             LogMessage("got wall texture %s\n", p->name);
  910.         }
  911.     }
  912.  
  913.     /* sort the names */
  914.     qsort( WTexture, NumWTexture, sizeof( char *), SortTextures);
  915. }
  916.  
  917.  
  918.  
  919. /*
  920.    forget the wall texture names
  921.    */
  922.  
  923. void ForgetWTextureNames()
  924. {
  925.     FreeMemory( _WTexture);
  926.     NumWTexture = 0;
  927.     FreeMemory( WTexture);
  928. }
  929.  
  930. /*
  931.    read in the floor/ceiling texture names
  932.    */
  933.  
  934. void ReadFTextureNames()
  935. {
  936.     SList p;
  937.  
  938.     printf("Reading floor/ceiling texture names\n");
  939.     FTexture = (char **)GetMemory(1);
  940.     
  941.     for(p = Ftexture_sections; p; p = p->next)
  942.         ReadFTextureNamesIn(p->string);
  943.     
  944.     qsort( FTexture, NumFTexture, sizeof( char *), SortTextures);
  945. }
  946.  
  947. void ReadFTextureNamesIn(char *section)
  948. {
  949.     MDirPtr dir;
  950.     BCINT n, m;
  951.     char start[16];
  952.     char end[16];
  953.  
  954.     strcpy(start, section); strcat(start, "_START");
  955.     strcpy(end, section); strcat(end, "_END"); 
  956.  
  957.     /* count the names */
  958.     dir = FindMasterDir( MasterDir, start);
  959.     dir = dir->next;
  960.     for (n = 0; dir && strcmp(dir->dir.name, end); n++)
  961.         dir = dir->next;
  962.     /* get the actual names from master dir. */
  963.     dir = FindMasterDir( MasterDir, start);
  964.     dir = dir->next;
  965.     FTexture = (char**)ResizeMemory( FTexture, (NumFTexture + n) * sizeof( char *));
  966.     for (m = 0; m < n; m++) {
  967.         FTexture[ NumFTexture + m] = (char*)GetMemory( 9 * sizeof( char));
  968.         strncpy( FTexture[ NumFTexture + m], dir->dir.name, 8);
  969.         FTexture[ NumFTexture + m][ 8] = '\0';
  970.         dir = dir->next;
  971.     }
  972.     NumFTexture += n;
  973.     
  974. }
  975.  
  976.  
  977.  
  978. /*
  979.    forget the floor/ceiling texture names
  980.    */
  981.  
  982. void ForgetFTextureNames()
  983. {
  984.     BCINT n;
  985.     
  986.     /* forget all names */
  987.     for (n = 0; n < NumFTexture; n++)
  988.         FreeMemory( FTexture[ n]);
  989.     
  990.     /* forget the array */
  991.     NumFTexture = 0;
  992.     FreeMemory( FTexture);
  993. }
  994.  
  995.  
  996.  
  997. /* end of file */
  998.